Initial commit. Unusable Marlin 2.0.5.3 core without any custimization.

This commit is contained in:
Knutwurst
2020-06-02 11:44:35 +02:00
commit 987c858ae4
1519 changed files with 1361431 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfig.h"
#if ENABLED(EEPROM_SETTINGS)
#include "../HAL/shared/eeprom_api.h"
#endif
class MarlinSettings {
public:
static uint16_t datasize();
static void reset();
static bool save(); // Return 'true' if data was saved
FORCE_INLINE static bool init_eeprom() {
reset();
#if ENABLED(EEPROM_SETTINGS)
const bool success = save();
#if ENABLED(EEPROM_CHITCHAT)
if (success) report();
#endif
return success;
#else
return true;
#endif
}
#if ENABLED(SD_FIRMWARE_UPDATE)
static bool sd_update_status(); // True if the SD-Firmware-Update EEPROM flag is set
static bool set_sd_update_status(const bool enable); // Return 'true' after EEPROM is set (-> always true)
#endif
#if ENABLED(EEPROM_SETTINGS)
static bool load(); // Return 'true' if data was loaded ok
static bool validate(); // Return 'true' if EEPROM data is ok
static inline void first_load() {
static bool loaded = false;
if (!loaded && load()) loaded = true;
}
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
// That can store is enabled
static uint16_t meshes_start_index();
FORCE_INLINE static uint16_t meshes_end_index() { return meshes_end; }
static uint16_t calc_num_meshes();
static int mesh_slot_offset(const int8_t slot);
static void store_mesh(const int8_t slot);
static void load_mesh(const int8_t slot, void * const into=nullptr);
//static void delete_mesh(); // necessary if we have a MAT
//static void defrag_meshes(); // "
#endif
#else
FORCE_INLINE
static bool load() { reset(); report(); return true; }
FORCE_INLINE
static void first_load() { (void)load(); }
#endif
#if DISABLED(DISABLE_M503)
static void report(const bool forReplay=false);
#else
FORCE_INLINE
static void report(const bool=false) {}
#endif
private:
static void postprocess();
#if ENABLED(EEPROM_SETTINGS)
static bool eeprom_error, validating;
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
// That can store is enabled
static const uint16_t meshes_end; // 128 is a placeholder for the size of the MAT; the MAT will always
// live at the very end of the eeprom
#endif
static bool _load();
static bool size_error(const uint16_t size);
#endif
};
extern MarlinSettings settings;

294
Marlin/src/module/delta.cpp Executable file
View File

@@ -0,0 +1,294 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* delta.cpp
*/
#include "../inc/MarlinConfig.h"
#if ENABLED(DELTA)
#include "delta.h"
#include "motion.h"
// For homing:
#include "planner.h"
#include "endstops.h"
#include "../lcd/ultralcd.h"
#include "../MarlinCore.h"
#if HAS_BED_PROBE
#include "probe.h"
#endif
#if ENABLED(SENSORLESS_HOMING)
#include "../feature/tmc_util.h"
#include "stepper/indirection.h"
#endif
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../core/debug_out.h"
// Initialized by settings.load()
float delta_height;
abc_float_t delta_endstop_adj{0};
float delta_radius,
delta_diagonal_rod,
delta_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;
float delta_safe_distance_from_top();
/**
* Recalculate factors used for delta kinematics whenever
* 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;
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));
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
*
* Calculate the tower positions for a given machine
* position, storing the result in the delta[] array.
*
* This is an expensive calculation, requiring 3 square
* roots per segmented linear move, and strains the limits
* of a Mega2560 with a Graphical Display.
*
* Suggested optimizations include:
*
* - Disable the home_offset (M206) and/or position_shift (G92)
* features to remove up to 12 float additions.
*/
#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); \
}while(0)
void inverse_kinematics(const xyz_pos_t &raw) {
#if HAS_HOTEND_OFFSET
// Delta hotend offsets must be applied in Cartesian space with no "spoofing"
xyz_pos_t pos = { raw.x - hotend_offset[active_extruder].x,
raw.y - hotend_offset[active_extruder].y,
raw.z };
DELTA_IK(pos);
//DELTA_DEBUG(pos);
#else
DELTA_IK(raw);
//DELTA_DEBUG(raw);
#endif
}
/**
* Calculate the highest Z position where the
* effector has the full range of XY motion.
*/
float delta_safe_distance_from_top() {
xyz_pos_t cartesian{0};
inverse_kinematics(cartesian);
const float centered_extent = delta.a;
cartesian.y = DELTA_PRINTABLE_RADIUS;
inverse_kinematics(cartesian);
return ABS(centered_extent - delta.a);
}
/**
* Delta Forward Kinematics
*
* See the Wikipedia article "Trilateration"
* https://en.wikipedia.org/wiki/Trilateration
*
* Establish a new coordinate system in the plane of the
* three carriage points. This system has its origin at
* tower1, with tower2 on the X axis. Tower3 is in the X-Y
* plane with a Z component of zero.
* We will define unit vectors in this coordinate system
* in our original coordinate system. Then when we calculate
* the Xnew, Ynew and Znew values, we can translate back into
* the original system by moving along those unit vectors
* by the corresponding values.
*
* Variable names matched to Marlin, c-version, and avoid the
* use of any vector library.
*
* by Andreas Hardtung 2016-06-07
* based on a Java function from "Delta Robot Kinematics V3"
* by Steve Graves
*
* The result is stored in the cartes[] array.
*/
void forward_kinematics_DELTA(const float &z1, const float &z2, const float &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 },
// Get the reciprocal of Magnitude of vector.
d2 = sq(p12[0]) + sq(p12[1]) + sq(p12[2]), inv_d = RSQRT(d2),
// Create unit vector by multiplying by the inverse of the magnitude.
ex[3] = { p12[0] * inv_d, p12[1] * inv_d, p12[2] * inv_d },
// Get the vector from the origin of the new system to the third point.
p13[3] = { delta_tower[C_AXIS].x - delta_tower[A_AXIS].x, delta_tower[C_AXIS].y - delta_tower[A_AXIS].y, z3 - z1 },
// Use the dot product to find the component of this vector on the X axis.
i = ex[0] * p13[0] + ex[1] * p13[1] + ex[2] * p13[2],
// Create a vector along the x axis that represents the x component of p13.
iex[3] = { ex[0] * i, ex[1] * i, ex[2] * i };
// Subtract the X component from the original vector leaving only Y. We use the
// variable that will be the unit vector after we scale it.
float ey[3] = { p13[0] - iex[0], p13[1] - iex[1], p13[2] - iex[2] };
// The magnitude and the inverse of the magnitude of Y component
const float j2 = sq(ey[0]) + sq(ey[1]) + sq(ey[2]), inv_j = RSQRT(j2);
// Convert to a unit vector
ey[0] *= inv_j; ey[1] *= inv_j; ey[2] *= inv_j;
// The cross product of the unit x and y is the unit z
// float[] ez = vectorCrossProd(ex, ey);
const float ez[3] = {
ex[1] * ey[2] - ex[2] * ey[1],
ex[2] * ey[0] - ex[0] * ey[2],
ex[0] * ey[1] - ex[1] * ey[0]
},
// We now have the d, i and j values defined in Wikipedia.
// Plug them into the equations defined in Wikipedia for Xnew, Ynew and Znew
Xnew = (delta_diagonal_rod_2_tower.a - delta_diagonal_rod_2_tower.b + d2) * inv_d * 0.5,
Ynew = ((delta_diagonal_rod_2_tower.a - delta_diagonal_rod_2_tower.c + sq(i) + j2) * 0.5 - i * Xnew) * inv_j,
Znew = SQRT(delta_diagonal_rod_2_tower.a - HYPOT2(Xnew, Ynew));
// Start from the origin of the old coordinates and add vectors in the
// old coords that represent the Xnew, Ynew and Znew to find the point
// in the old system.
cartes.set(delta_tower[A_AXIS].x + ex[0] * Xnew + ey[0] * Ynew - ez[0] * Znew,
delta_tower[A_AXIS].y + ex[1] * Xnew + ey[1] * Ynew - ez[1] * Znew,
z1 + ex[2] * Xnew + ey[2] * Ynew - ez[2] * Znew);
}
/**
* A delta can only safely home all axes at the same time
* This is like quick_home_xy() but for 3 towers.
*/
void home_delta() {
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
// 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)
sensorless_t stealth_states {
tmc_enable_stallguard(stepperX),
tmc_enable_stallguard(stepperY),
tmc_enable_stallguard(stepperZ)
};
#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
);
line_to_current_position(homing_feedrate(Z_AXIS));
planner.synchronize();
// 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);
#endif
endstops.validate_homing_move();
// At least one carriage has reached the top.
// Now re-home each carriage separately.
homeaxis(A_AXIS);
homeaxis(B_AXIS);
homeaxis(C_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_XYZ(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 (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

128
Marlin/src/module/delta.h Executable file
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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* delta.h - Delta-specific functions
*/
#include "../core/types.h"
#include "../core/macros.h"
extern float delta_height;
extern abc_float_t delta_endstop_adj;
extern float delta_radius,
delta_diagonal_rod,
delta_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;
/**
* Recalculate factors used for delta kinematics whenever
* settings have been changed (e.g., by M665).
*/
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
*
* Calculate the tower positions for a given machine
* position, storing the result in the delta[] array.
*
* This is an expensive calculation, requiring 3 square
* roots per segmented linear move, and strains the limits
* of a Mega2560 with a Graphical Display.
*
* Suggested optimizations include:
*
* - Disable the home_offset (M206) and/or position_shift (G92)
* features to remove up to 12 float additions.
*
* - Use a fast-inverse-sqrt function and add the reciprocal.
* (see above)
*/
// Macro to obtain the Z position of an individual tower
#define DELTA_Z(V,T) V.z + SQRT( \
delta_diagonal_rod_2_tower[T] - HYPOT2( \
delta_tower[T].x - V.x, \
delta_tower[T].y - V.y \
) \
)
#define DELTA_IK(V) delta.set(DELTA_Z(V, A_AXIS), DELTA_Z(V, B_AXIS), DELTA_Z(V, C_AXIS))
void inverse_kinematics(const xyz_pos_t &raw);
/**
* Calculate the highest Z position where the
* effector has the full range of XY motion.
*/
float delta_safe_distance_from_top();
/**
* Delta Forward Kinematics
*
* See the Wikipedia article "Trilateration"
* https://en.wikipedia.org/wiki/Trilateration
*
* Establish a new coordinate system in the plane of the
* three carriage points. This system has its origin at
* tower1, with tower2 on the X axis. Tower3 is in the X-Y
* plane with a Z component of zero.
* We will define unit vectors in this coordinate system
* in our original coordinate system. Then when we calculate
* the Xnew, Ynew and Znew values, we can translate back into
* the original system by moving along those unit vectors
* by the corresponding values.
*
* Variable names matched to Marlin, c-version, and avoid the
* use of any vector library.
*
* by Andreas Hardtung 2016-06-07
* based on a Java function from "Delta Robot Kinematics V3"
* by Steve Graves
*
* The result is stored in the cartes[] array.
*/
void forward_kinematics_DELTA(const float &z1, const float &z2, const float &z3);
FORCE_INLINE void forward_kinematics_DELTA(const abc_float_t &point) {
forward_kinematics_DELTA(point.a, point.b, point.c);
}
void home_delta();

1003
Marlin/src/module/endstops.cpp Executable file

File diff suppressed because it is too large Load Diff

196
Marlin/src/module/endstops.h Executable file
View File

@@ -0,0 +1,196 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* endstops.h - manages endstops
*/
#include "../inc/MarlinConfig.h"
#include <stdint.h>
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
};
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;
#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
#if ENDSTOP_NOISE_THRESHOLD
static esbits_t validated_live_state;
static uint8_t endstop_poll_count; // Countdown from threshold for polling
#endif
public:
Endstops() {};
/**
* Initialize the endstop pins
*/
static void init();
/**
* 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
);
}
static inline bool global_enabled() { return enabled_globally; }
/**
* Periodic call to poll endstops if required. Called from temperature ISR
*/
static void poll();
/**
* Update endstops bits from the pins. Apply filtering to get a verified state.
* If abort_enabled() and moving towards a triggered switch, abort the current move.
* Called from ISR contexts.
*/
static void update();
/**
* Get Endstop hit state.
*/
FORCE_INLINE static uint8_t trigger_state() { return hit_state; }
/**
* Get current endstops state
*/
FORCE_INLINE static esbits_t state() {
return
#if ENDSTOP_NOISE_THRESHOLD
validated_live_state
#else
live_state
#endif
;
}
/**
* Report endstop hits to serial. Called from loop().
*/
static void event_handler();
/**
* Report endstop states in response to M119
*/
static void report_states();
// Enable / disable endstop checking globally
static void enable_globally(const bool onoff=true);
// Enable / disable endstop checking
static void enable(const bool onoff=true);
// Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable
static void not_homing();
#if ENABLED(VALIDATE_HOMING_ENDSTOPS)
// If the last move failed to trigger an endstop, call kill
static void validate_homing_move();
#else
FORCE_INLINE static void validate_homing_move() { hit_on_purpose(); }
#endif
// Clear endstops (i.e., they were hit intentionally) to suppress the report
FORCE_INLINE static void hit_on_purpose() { hit_state = 0; }
// Enable / disable endstop z-probe checking
#if HAS_BED_PROBE
static volatile bool z_probe_enabled;
static void enable_z_probe(const bool onoff=true);
#endif
static void resync();
// Debugging of endstops
#if ENABLED(PINS_DEBUGGING)
static bool monitor_flag;
static void monitor();
static void run_monitor();
#endif
#if ENABLED(SPI_ENDSTOPS)
typedef struct {
union {
bool any;
struct { bool x:1, y:1, z:1; };
};
} tmc_spi_homing_t;
static tmc_spi_homing_t tmc_spi_homing;
static void clear_endstop_state();
static bool tmc_spi_homing_check();
#endif
};
extern Endstops endstops;
/**
* A class to save and change the endstop state,
* then restore it when it goes out of scope.
*/
class TemporaryGlobalEndstopsState {
bool saved;
public:
TemporaryGlobalEndstopsState(const bool enable) : saved(endstops.global_enabled()) {
endstops.enable_globally(enable);
}
~TemporaryGlobalEndstopsState() { endstops.enable_globally(saved); }
};

1833
Marlin/src/module/motion.cpp Executable file

File diff suppressed because it is too large Load Diff

394
Marlin/src/module/motion.h Executable file
View File

@@ -0,0 +1,394 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* motion.h
*
* High-level motion commands to feed the planner
* Some of these methods may migrate to the planner class.
*/
#include "../inc/MarlinConfig.h"
#if IS_SCARA
#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;
extern bool relative_mode;
extern xyze_pos_t current_position, // High-level current tool position
destination; // Destination for a move
// 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];
#endif
// Scratch space for a cartesian result
extern xyz_pos_t cartes;
// Until kinematics.cpp is created, declare this here
#if IS_KINEMATIC
extern abc_pos_t delta;
#endif
#if HAS_ABL_NOT_UBL
extern float 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)
#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 };
#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]); }
feedRate_t get_homing_bump_feedrate(const AxisEnum axis);
extern feedRate_t feedrate_mm_s;
/**
* Feedrate scaling
*/
extern int16_t feedrate_percentage;
// The active extruder (tool). Set with T<extruder> command.
#if EXTRUDERS > 1
extern uint8_t active_extruder;
#else
constexpr uint8_t active_extruder = 0;
#endif
#if ENABLED(LCD_SHOW_E_TOTAL)
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); }
#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]); }
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);
#if HAS_WORKSPACE_OFFSET
void update_workspace_offset(const AxisEnum axis);
#else
#define update_workspace_offset(x) NOOP
#endif
#if HAS_HOTEND_OFFSET
extern xyz_pos_t hotend_offset[HOTENDS];
void reset_hotend_offsets();
#elif HOTENDS
constexpr xyz_pos_t hotend_offset[HOTENDS] = { { 0 } };
#else
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;
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 update_software_endstops(...) NOOP
#endif
void report_real_position();
void report_current_position();
void report_current_position_projected();
void get_cartesian_from_steppers();
void set_current_from_steppers_for_axis(const AxisEnum axis);
/**
* 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();
/**
* 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);
#if EXTRUDERS
void unscaled_e_move(const float &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
);
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));
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
/**
* 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_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_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); }
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); }
void remember_feedrate_and_scaling();
void remember_feedrate_scaling_off();
void restore_feedrate_and_scaling();
//
// Homing
//
uint8_t axes_need_homing(uint8_t axis_bits=0x07);
bool axis_unhomed_error(uint8_t axis_bits=0x07);
#if ENABLED(NO_MOTION_BEFORE_HOMING)
#define MOTION_CONDITIONS (IsRunning() && !axis_unhomed_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);
/**
* Workspace offsets
*/
#if HAS_HOME_OFFSET || HAS_POSITION_SHIFT
#if HAS_HOME_OFFSET
extern xyz_pos_t home_offset;
#endif
#if HAS_POSITION_SHIFT
extern xyz_pos_t position_shift;
#endif
#if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
extern xyz_pos_t workspace_offset;
#define _WS workspace_offset
#elif HAS_HOME_OFFSET
#define _WS home_offset
#else
#define _WS position_shift
#endif
#define NATIVE_TO_LOGICAL(POS, AXIS) ((POS) + _WS[AXIS])
#define LOGICAL_TO_NATIVE(POS, AXIS) ((POS) - _WS[AXIS])
FORCE_INLINE void toLogical(xy_pos_t &raw) { raw += _WS; }
FORCE_INLINE void toLogical(xyz_pos_t &raw) { raw += _WS; }
FORCE_INLINE void toLogical(xyze_pos_t &raw) { raw += _WS; }
FORCE_INLINE void toNative(xy_pos_t &raw) { raw -= _WS; }
FORCE_INLINE void toNative(xyz_pos_t &raw) { raw -= _WS; }
FORCE_INLINE void toNative(xyze_pos_t &raw) { raw -= _WS; }
#else
#define NATIVE_TO_LOGICAL(POS, AXIS) (POS)
#define LOGICAL_TO_NATIVE(POS, AXIS) (POS)
FORCE_INLINE void toLogical(xy_pos_t&) {}
FORCE_INLINE void toLogical(xyz_pos_t&) {}
FORCE_INLINE void toLogical(xyze_pos_t&) {}
FORCE_INLINE void toNative(xy_pos_t&) {}
FORCE_INLINE void toNative(xyz_pos_t&) {}
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)
/**
* position_is_reachable family of functions
*/
#if IS_KINEMATIC // (DELTA or SCARA)
#if HAS_SCARA_OFFSET
extern abc_pos_t scara_home_offset; // A and B angular offsets, Z mm offset
#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) {
#if ENABLED(DELTA)
return HYPOT2(rx, ry) <= sq(DELTA_PRINTABLE_RADIUS - inset + fslop);
#elif IS_SCARA
const float R2 = HYPOT2(rx - SCARA_OFFSET_X, ry - SCARA_OFFSET_Y);
return (
R2 <= sq(L1 + L2) - inset
#if MIDDLE_DEAD_ZONE_R > 0
&& R2 >= sq(float(MIDDLE_DEAD_ZONE_R))
#endif
);
#endif
}
inline bool position_is_reachable(const xy_pos_t &pos, const float inset=0) {
return position_is_reachable(pos.x, pos.y, inset);
}
#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;
#if ENABLED(DUAL_X_CARRIAGE)
if (active_extruder)
return WITHIN(rx, X2_MIN_POS - fslop, X2_MAX_POS + fslop);
else
return WITHIN(rx, X1_MIN_POS - fslop, X1_MAX_POS + fslop);
#else
return WITHIN(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); }
#endif // CARTESIAN
/**
* 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
#endif
/**
* Dual X Carriage
*/
#if ENABLED(DUAL_X_CARRIAGE)
enum DualXMode : char {
DXC_FULL_CONTROL_MODE,
DXC_AUTO_PARK_MODE,
DXC_DUPLICATION_MODE,
DXC_MIRRORED_MODE
};
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
FORCE_INLINE bool dxc_is_duplicating() { return dual_x_carriage_mode >= DXC_DUPLICATION_MODE; }
float x_home_pos(const int extruder);
FORCE_INLINE int x_home_dir(const uint8_t extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
#else
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
enum DualXMode : char { DXC_DUPLICATION_MODE = 2 };
#endif
FORCE_INLINE int x_home_dir(const uint8_t) { return home_dir(X_AXIS); }
#endif
#if HAS_M206_COMMAND
void set_home_offset(const AxisEnum axis, const float v);
#endif

2935
Marlin/src/module/planner.cpp Executable file

File diff suppressed because it is too large Load Diff

902
Marlin/src/module/planner.h Executable file
View File

@@ -0,0 +1,902 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* planner.h
*
* Buffer movement commands and manage the acceleration profile plan
*
* Derived from Grbl
* Copyright (c) 2009-2011 Simen Svale Skogsrud
*/
#include "../MarlinCore.h"
#include "motion.h"
#include "../gcode/queue.h"
#if ENABLED(DELTA)
#include "delta.h"
#endif
#if ABL_PLANAR
#include "../libs/vector_3.h" // for matrix_3x3
#endif
#if ENABLED(FWRETRACT)
#include "../feature/fwretract.h"
#endif
#if ENABLED(MIXING_EXTRUDER)
#include "../feature/mixing.h"
#endif
#if HAS_CUTTER
#include "../feature/spindle_laser.h"
#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 };
#endif
#if IS_KINEMATIC && DISABLED(CLASSIC_JERK)
#define HAS_DIST_MM_ARG 1
#endif
enum BlockFlagBit : char {
// Recalculate trapezoids on entry junction. For optimization.
BLOCK_BIT_RECALCULATE,
// Nominal speed always reached.
// i.e., The segment is long enough, so the nominal speed is reachable if accelerating
// from a safe speed (in consideration of jerking from zero speed).
BLOCK_BIT_NOMINAL_LENGTH,
// The block is segment 2+ of a longer move
BLOCK_BIT_CONTINUED,
// Sync the stepper counts from the block
BLOCK_BIT_SYNC_POSITION
};
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)
};
/**
* struct block_t
*
* A single entry in the planner buffer.
* Tracks linear movement over multiple axes.
*
* The "nominal" values are as-specified by gcode, and
* may never actually be reached due to acceleration limits.
*/
typedef struct block_t {
volatile uint8_t flag; // Block flags (See BlockFlag enum above) - Modified by ISR and main thread!
// Fields used by the motion planner to manage acceleration
float nominal_speed_sqr, // The nominal speed for this block in (mm/sec)^2
entry_speed_sqr, // Entry speed at previous-current junction in (mm/sec)^2
max_entry_speed_sqr, // Maximum allowable junction entry speed in (mm/sec)^2
millimeters, // The total travel of this block in mm
acceleration; // acceleration mm/sec^2
union {
abce_ulong_t steps; // Step count along each axis
abce_long_t position; // New position to force when this sync block is executed
};
uint32_t step_event_count; // The number of step events required to complete this block
#if EXTRUDERS > 1
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
#endif
// Settings for the trapezoid generator
uint32_t accelerate_until, // The index of the step event on which to stop acceleration
decelerate_after; // The index of the step event on which to start decelerating
#if ENABLED(S_CURVE_ACCELERATION)
uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
acceleration_time, // Acceleration time and deceleration time in STEP timer counts
deceleration_time,
acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
deceleration_time_inverse;
#else
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)
// Advance extrusion
#if ENABLED(LIN_ADVANCE)
bool use_advance_lead;
uint16_t advance_speed, // STEP timer value for extruder speed offset ISR
max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!)
final_adv_steps; // advance steps due to exit speed
float e_D_ratio;
#endif
uint32_t nominal_rate, // The nominal step rate for this block in step_events/sec
initial_rate, // The jerk-adjusted step rate at start of block
final_rate, // The minimal rate at exit
acceleration_steps_per_s2; // acceleration steps/sec^2
#if HAS_CUTTER
cutter_power_t cutter_power; // Power level for Spindle, Laser, etc.
#endif
#if FAN_COUNT > 0
uint8_t fan_speed[FAN_COUNT];
#endif
#if ENABLED(BARICUDA)
uint8_t valve_pressure, e_to_p_pressure;
#endif
#if HAS_SPI_LCD
uint32_t segment_time_us;
#endif
#if ENABLED(POWER_LOSS_RECOVERY)
uint32_t sdpos;
#endif
} block_t;
#define HAS_POSITION_FLOAT ANY(LIN_ADVANCE, SCARA_FEEDRATE_SCALING, GRADIENT_MIX, LCD_SHOW_E_TOTAL)
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
typedef struct {
uint32_t max_acceleration_mm_per_s2[XYZE_N], // (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 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.
feedRate_t min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate
min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate
} planner_settings_t;
#if DISABLED(SKEW_CORRECTION)
#define XY_SKEW_FACTOR 0
#define XZ_SKEW_FACTOR 0
#define YZ_SKEW_FACTOR 0
#endif
typedef struct {
#if ENABLED(SKEW_CORRECTION_GCODE)
float xy;
#if ENABLED(SKEW_CORRECTION_FOR_Z)
float xz, yz;
#else
const float xz = XZ_SKEW_FACTOR, yz = YZ_SKEW_FACTOR;
#endif
#else
const float xy = XY_SKEW_FACTOR,
xz = XZ_SKEW_FACTOR, yz = YZ_SKEW_FACTOR;
#endif
} skew_factor_t;
class Planner {
public:
/**
* The move buffer, calculated in stepper steps
*
* block_buffer is a ring buffer...
*
* head,tail : indexes for write,read
* head==tail : the buffer is empty
* head!=tail : blocks are in the buffer
* head==(tail-1)%size : the buffer is full
*
* Writer of head is Planner::buffer_segment().
* Reader of tail is Stepper::isr(). Always consider tail busy / read-only
*/
static block_t block_buffer[BLOCK_BUFFER_SIZE];
static volatile uint8_t block_buffer_head, // Index of the next block to be pushed
block_buffer_nonbusy, // Index of the first non busy block
block_buffer_planned, // Index of the optimally planned block
block_buffer_tail; // Index of the busy block, if any
static uint16_t cleaning_buffer_counter; // A counter to disable queuing of blocks
static uint8_t delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
#if ENABLED(DISTINCT_E_FACTORS)
static uint8_t last_extruder; // Respond to extruder change
#endif
#if 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
#if DISABLED(NO_VOLUMETRICS)
static float filament_size[EXTRUDERS], // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
volumetric_area_nominal, // Nominal cross-sectional area
volumetric_multiplier[EXTRUDERS]; // Reciprocal of cross-sectional area of filament (in mm^2). Pre-calculated to reduce computation in the planner
// May be auto-adjusted by a filament width sensor
#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 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
;
#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
#endif
#if HAS_LEVELING
static bool leveling_active; // Flag that bed leveling is enabled
#if ABL_PLANAR
static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
#endif
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
static float z_fade_height, inverse_z_fade_height;
#endif
#else
static constexpr bool leveling_active = false;
#endif
#if ENABLED(LIN_ADVANCE)
static float extruder_advance_K[EXTRUDERS];
#endif
/**
* The current position of the tool in absolute steps
* Recalculated if any axis_steps_per_mm are changed by gcode
*/
static xyze_long_t position;
#if HAS_POSITION_FLOAT
static xyze_pos_t position_float;
#endif
#if IS_KINEMATIC
static xyze_pos_t position_cart;
#endif
static skew_factor_t skew_factor;
#if ENABLED(SD_ABORT_ON_ENDSTOP_HIT)
static bool abort_on_endstop_hit;
#endif
private:
/**
* Speed of previous path line segment
*/
static xyze_float_t previous_speed;
/**
* Nominal speed of previous path line segment (mm/s)^2
*/
static float previous_nominal_speed_sqr;
/**
* Limit where 64bit math is necessary for acceleration calculation
*/
static uint32_t cutoff_long;
#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];
#endif
#if HAS_SPI_LCD
volatile static uint32_t block_buffer_runtime_us; //Theoretical block buffer runtime in µs
#endif
public:
/**
* Instance Methods
*/
Planner();
void init();
/**
* Static (class) Methods
*/
static void reset_acceleration_rates();
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);
#if 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
);
}
#endif
// Manage fans, paste pressure, etc.
static void check_axes_activity();
// Update multipliers based on new diameter measurements
static void calculate_volumetric_multipliers();
#if ENABLED(FILAMENT_WIDTH_SENSOR)
void apply_filament_width_sensor(const int8_t encoded_ratio);
static inline float volumetric_percent(const bool vol) {
return 100.0f * (vol
? volumetric_area_nominal / volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
: volumetric_multiplier[FILAMENT_SENSOR_EXTRUDER_NUM]
);
}
#endif
#if DISABLED(NO_VOLUMETRICS)
FORCE_INLINE static void set_filament_size(const uint8_t e, const float &v) {
filament_size[e] = v;
// 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;
}
#endif
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
/**
* Get the Z leveling fade factor based on the given Z height,
* re-calculating only when needed.
*
* 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 float z_fade_factor = 1;
if (!z_fade_height) return 1;
if (rz >= z_fade_height) return 0;
if (last_fade_z != rz) {
last_fade_z = rz;
z_fade_factor = 1 - rz * inverse_z_fade_height;
}
return z_fade_factor;
}
FORCE_INLINE static void force_fade_recalc() { last_fade_z = -999.999f; }
FORCE_INLINE static void set_z_fade_height(const float &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) {
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 bool leveling_active_at_z(const float&) { 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)) {
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)) {
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)) {
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)) {
cx = sx; cy = sy;
}
}
}
FORCE_INLINE static void unskew(xyz_pos_t &raw) { unskew(raw.x, raw.y, raw.z); }
#endif // SKEW_CORRECTION
#if HAS_LEVELING
/**
* Apply leveling to transform a cartesian position
* as it will be given to the planner and steppers.
*/
static void apply_leveling(xyz_pos_t &raw);
static void unapply_leveling(xyz_pos_t &raw);
FORCE_INLINE static void force_unapply_leveling(xyz_pos_t &raw) {
leveling_active = true;
unapply_leveling(raw);
leveling_active = false;
}
#endif
#if ENABLED(FWRETRACT)
static void apply_retract(float &rz, float &e);
FORCE_INLINE static void apply_retract(xyze_pos_t &raw) { apply_retract(raw.z, raw.e); }
static void unapply_retract(float &rz, float &e);
FORCE_INLINE static void unapply_retract(xyze_pos_t &raw) { unapply_retract(raw.z, raw.e); }
#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 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
}
#endif // HAS_POSITION_MODIFIERS
// Number of moves currently in the planner including the busy block, if any
FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); }
// Number of nonbusy moves currently in the planner
FORCE_INLINE static uint8_t nonbusy_movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_nonbusy); }
// Remove all blocks from the buffer
FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0; }
// Check if movement queue is full
FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
// Get count of movement slots free
FORCE_INLINE static uint8_t moves_free() { return BLOCK_BUFFER_SIZE - 1 - movesplanned(); }
/**
* Planner::get_next_free_block
*
* - Get the next head indices (passed by reference)
* - Wait for the number of spaces to open up in the planner
* - Return the first head block
*/
FORCE_INLINE static block_t* get_next_free_block(uint8_t &next_buffer_head, const uint8_t count=1) {
// Wait until there are enough slots free
while (moves_free() < count) { idle(); }
// Return the first available block
next_buffer_head = next_block_index(block_buffer_head);
return &block_buffer[block_buffer_head];
}
/**
* Planner::_buffer_steps
*
* Add a new linear movement to the buffer (in terms of steps).
*
* target - target position in steps units
* fr_mm_s - (target) speed of the move
* extruder - target extruder
* millimeters - the length of the movement, if known
*
* 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
);
/**
* Planner::_populate_block
*
* Fills a new linear movement in the block (in terms of steps).
*
* target - target position in steps units
* fr_mm_s - (target) speed of the move
* extruder - target extruder
* millimeters - the length of the movement, if known
*
* 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
);
/**
* Planner::buffer_sync_block
* Add a block to the buffer that just updates the position
*/
static void buffer_sync_block();
#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);
#endif
/**
* Planner::buffer_segment
*
* Add a new linear movement to the buffer in axis units.
*
* Leveling and kinematics should be applied ahead of calling this.
*
* a,b,c,e - target positions in mm and/or degrees
* fr_mm_s - (target) speed of the move
* 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
);
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:
/**
* Add a new linear movement to the buffer.
* The target is cartesian. It's translated to
* delta/scara if needed.
*
* rx,ry,rz,e - 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
);
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
);
}
/**
* Set the planner.position and individual stepper positions.
* Used by G92, G28, G29, and other procedures.
*
* The supplied position is in the cartesian coordinate space and is
* translated in to machine space as needed. Modifiers such as leveling
* and skew are also applied.
*
* Multiplies by axis_steps_per_mm[] and does necessary conversion
* for COREXY / COREXZ / COREYZ to set the corresponding stepper positions.
*
* 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);
/**
* Set the planner.position and individual stepper positions.
*
* 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); }
/**
* Get an axis position according to stepper position(s)
* For CORE machines apply translation from ABC to XYZ.
*/
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)
};
return out;
}
// SCARA AB axes are in degrees, not mm
#if IS_SCARA
FORCE_INLINE static float get_axis_position_degrees(const AxisEnum axis) { return get_axis_position_mm(axis); }
#endif
// Called to force a quick stop of the machine (for example, when
// 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
static void endstop_triggered(const AxisEnum axis);
// Triggered position of an axis in mm (not core-savvy)
static float triggered_position_mm(const AxisEnum axis);
// Block until all buffered steps are executed / cleaned
static void synchronize();
// Wait for moves to finish and disable all steppers
static void finish_and_disable();
// Periodic tick to handle cleaning timeouts
// 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
}
}
/**
* Does the buffer have any blocks queued?
*/
FORCE_INLINE static bool has_blocks_queued() { return (block_buffer_head != block_buffer_tail); }
/**
* Get the current block for processing
* and mark the block as busy.
* Return nullptr if the buffer is empty
* or if there is a first-block delay.
*
* WARNING: Called from Stepper ISR context!
*/
static block_t* get_current_block();
/**
* "Discard" the block and "release" the memory.
* Called when the current block is no longer needed.
*/
FORCE_INLINE static void discard_current_block() {
if (has_blocks_queued())
block_buffer_tail = next_block_index(block_buffer_tail);
}
#if HAS_SPI_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 bool autotemp_enabled;
static void getHighESpeed();
static void autotemp_M104_M109();
#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
}
#endif
private:
/**
* Get the index of the next / previous block in the ring buffer
*/
static constexpr uint8_t next_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index + 1); }
static constexpr uint8_t prev_block_index(const uint8_t block_index) { return BLOCK_MOD(block_index - 1); }
/**
* 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) {
if (accel == 0) return 0; // accel was 0, set acceleration distance to 0
return (sq(target_rate) - sq(initial_rate)) / (accel * 2);
}
/**
* Return the point at which you must start braking (at the rate of -'accel') if
* you start at 'initial_rate', accelerate (until reaching the point), and want to end at
* 'final_rate' after traveling 'distance'.
*
* 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) {
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);
}
/**
* Calculate the maximum allowable speed squared at this point, in order
* 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) {
return target_velocity_sqr - 2 * accel * distance;
}
#if ENABLED(S_CURVE_ACCELERATION)
/**
* Calculate the speed reached given initial speed, acceleration and distance
*/
static float final_speed(const float &initial_velocity, const float &accel, const float &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 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();
static void recalculate_trapezoids();
static void recalculate();
#if DISABLED(CLASSIC_JERK)
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]);
vector *= RSQRT(magnitude_sq);
}
FORCE_INLINE static float limit_value_by_axis_maximum(const float &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]));
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]))
extern Planner planner;

View File

@@ -0,0 +1,206 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* planner_bezier.cpp
*
* Compute and buffer movement commands for bezier curves
*
*/
#include "../inc/MarlinConfig.h"
#if ENABLED(BEZIER_CURVE_SUPPORT)
#include "planner.h"
#include "motion.h"
#include "temperature.h"
#include "../MarlinCore.h"
#include "../core/language.h"
#include "../gcode/queue.h"
// See the meaning in the documentation of cubic_b_spline().
#define MIN_STEP 0.002f
#define MAX_STEP 0.1f
#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; }
/**
* Compute a Bézier curve using the De Casteljau's algorithm (see
* https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm), which is
* 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) {
const float iab = interp(a, b, t),
ibc = interp(b, c, t),
icd = interp(c, d, t),
iabc = interp(iab, ibc, t),
ibcd = interp(ibc, icd, t);
return interp(iabc, ibcd, t);
}
/**
* 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); }
/**
* The algorithm for computing the step is loosely based on the one in Kig
* (See https://sources.debian.net/src/kig/4:15.08.3-1/misc/kigpainter.cpp/#L759)
* However, we do not use the stack.
*
* The algorithm goes as it follows: the parameters t runs from 0.0 to
* 1.0 describing the curve, which is evaluated by eval_bezier(). At
* each iteration we have to choose a step, i.e., the increment of the
* t variable. By default the step of the previous iteration is taken,
* and then it is enlarged or reduced depending on how straight the
* curve locally is. The step is always clamped between MIN_STEP/2 and
* 2*MAX_STEP. MAX_STEP is taken at the first iteration.
*
* For some t, the step value is considered acceptable if the curve in
* the interval [t, t+step] is sufficiently straight, i.e.,
* sufficiently close to linear interpolation. In practice the
* following test is performed: the distance between eval_bezier(...,
* t+step/2) is evaluated and compared with 0.5*(eval_bezier(...,
* t)+eval_bezier(..., t+step)). If it is smaller than SIGMA, then the
* step value is considered acceptable, otherwise it is not. The code
* seeks to find the larger step value which is considered acceptable.
*
* At every iteration the recorded step value is considered and then
* iteratively halved until it becomes acceptable. If it was already
* acceptable in the beginning (i.e., no halving were done), then
* maybe it was necessary to enlarge it; then it is iteratively
* doubled while it remains acceptable. The last acceptable value
* found is taken, provided that it is between MIN_STEP and MAX_STEP
* and does not bring t over 1.0.
*
* Caveat: this algorithm is not perfect, since it can happen that a
* step is considered acceptable even when the curve is not linear at
* all in the interval [t, t+step] (but its mid point coincides "by
* chance" with the midpoint according to the parametrization). This
* kind of glitches can be eliminated with proper first derivative
* estimates; however, given the improbability of such configurations,
* the mitigation offered by MIN_STEP and the small computational
* power available on Arduino, I think it is not wise to implement it.
*/
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 uint8_t extruder
) {
// Absolute first and second control points are recovered.
const xy_pos_t first = position + offsets[0], second = target + offsets[1];
xyze_pos_t bez_target;
bez_target.set(position.x, position.y);
float step = MAX_STEP;
millis_t next_idle_ms = millis() + 200UL;
for (float t = 0; t < 1;) {
thermalManager.manage_heater();
millis_t now = millis();
if (ELAPSED(now, next_idle_ms)) {
next_idle_ms = now + 200UL;
idle();
}
// First try to reduce the step in order to make it sufficiently
// close to a linear interpolation.
bool did_reduce = false;
float new_t = t + step;
NOMORE(new_t, 1);
float new_pos0 = eval_bezier(position.x, first.x, second.x, target.x, new_t),
new_pos1 = eval_bezier(position.y, first.y, second.y, target.y, new_t);
for (;;) {
if (new_t - t < (MIN_STEP)) break;
const float candidate_t = 0.5f * (t + new_t),
candidate_pos0 = eval_bezier(position.x, first.x, second.x, target.x, candidate_t),
candidate_pos1 = eval_bezier(position.y, first.y, second.y, target.y, candidate_t),
interp_pos0 = 0.5f * (bez_target.x + new_pos0),
interp_pos1 = 0.5f * (bez_target.y + new_pos1);
if (dist1(candidate_pos0, candidate_pos1, interp_pos0, interp_pos1) <= (SIGMA)) break;
new_t = candidate_t;
new_pos0 = candidate_pos0;
new_pos1 = candidate_pos1;
did_reduce = true;
}
// If we did not reduce the step, maybe we should enlarge it.
if (!did_reduce) for (;;) {
if (new_t - t > MAX_STEP) break;
const float candidate_t = t + 2 * (new_t - t);
if (candidate_t >= 1) break;
const float candidate_pos0 = eval_bezier(position.x, first.x, second.x, target.x, candidate_t),
candidate_pos1 = eval_bezier(position.y, first.y, second.y, target.y, candidate_t),
interp_pos0 = 0.5f * (bez_target.x + candidate_pos0),
interp_pos1 = 0.5f * (bez_target.y + candidate_pos1);
if (dist1(new_pos0, new_pos1, interp_pos0, interp_pos1) > (SIGMA)) break;
new_t = candidate_t;
new_pos0 = candidate_pos0;
new_pos1 = candidate_pos1;
}
// Check some postcondition; they are disabled in the actual
// Marlin build, but if you test the same code on a computer you
// may want to check they are respect.
/*
assert(new_t <= 1.0);
if (new_t < 1.0) {
assert(new_t - t >= (MIN_STEP) / 2.0);
assert(new_t - t <= (MAX_STEP) * 2.0);
}
*/
step = new_t - t;
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.
};
apply_motion_limits(new_bez);
bez_target = new_bez;
#if HAS_LEVELING && !PLANNER_LEVELING
xyze_pos_t pos = bez_target;
planner.apply_leveling(pos);
#else
const xyze_pos_t &pos = bez_target;
#endif
if (!planner.buffer_line(pos, scaled_fr_mm_s, active_extruder, step))
break;
}
}
#endif // BEZIER_CURVE_SUPPORT

View File

@@ -0,0 +1,39 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* planner_bezier.h
*
* Compute and buffer movement commands for Bézier curves
*
*/
#include "../core/types.h"
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 uint8_t extruder
);

View File

@@ -0,0 +1,362 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "../inc/MarlinConfig.h"
#if DISABLED(PRINTCOUNTER)
#include "../libs/stopwatch.h"
Stopwatch print_job_timer; // Global Print Job Timer instance
#else // PRINTCOUNTER
#if ENABLED(EXTENSIBLE_UI)
#include "../lcd/extui/ui_api.h"
#endif
#include "printcounter.h"
#include "../MarlinCore.h"
#include "../HAL/shared/eeprom_api.h"
#if HAS_BUZZER && SERVICE_WARNING_BUZZES > 0
#include "../libs/buzzer.h"
#endif
// Service intervals
#if HAS_SERVICE_INTERVALS
#if SERVICE_INTERVAL_1 > 0
#define SERVICE_INTERVAL_SEC_1 (3600UL * SERVICE_INTERVAL_1)
#else
#define SERVICE_INTERVAL_SEC_1 (3600UL * 100)
#endif
#if SERVICE_INTERVAL_2 > 0
#define SERVICE_INTERVAL_SEC_2 (3600UL * SERVICE_INTERVAL_2)
#else
#define SERVICE_INTERVAL_SEC_2 (3600UL * 100)
#endif
#if SERVICE_INTERVAL_3 > 0
#define SERVICE_INTERVAL_SEC_3 (3600UL * SERVICE_INTERVAL_3)
#else
#define SERVICE_INTERVAL_SEC_3 (3600UL * 100)
#endif
#endif
PrintCounter print_job_timer; // Global Print Job Timer instance
printStatistics PrintCounter::data;
const PrintCounter::eeprom_address_t PrintCounter::address = STATS_EEPROM_ADDRESS;
millis_t PrintCounter::lastDuration;
bool PrintCounter::loaded = false;
millis_t PrintCounter::deltaDuration() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("deltaDuration"));
#endif
millis_t tmp = lastDuration;
lastDuration = duration();
return lastDuration - tmp;
}
void PrintCounter::incFilamentUsed(float const &amount) {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("incFilamentUsed"));
#endif
// Refuses to update data if object is not loaded
if (!isLoaded()) return;
data.filamentUsed += amount; // mm
}
void PrintCounter::initStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("initStats"));
#endif
loaded = true;
data = { 0, 0, 0, 0, 0.0
#if HAS_SERVICE_INTERVALS
#if SERVICE_INTERVAL_1 > 0
, SERVICE_INTERVAL_SEC_1
#endif
#if SERVICE_INTERVAL_2 > 0
, SERVICE_INTERVAL_SEC_2
#endif
#if SERVICE_INTERVAL_3 > 0
, SERVICE_INTERVAL_SEC_3
#endif
#endif
};
saveStats();
persistentStore.access_start();
persistentStore.write_data(address, (uint8_t)0x16);
persistentStore.access_finish();
}
#if HAS_SERVICE_INTERVALS
inline void _print_divider() { SERIAL_ECHO_MSG("============================================="); }
inline bool _service_warn(const char * const msg) {
_print_divider();
SERIAL_ECHO_START();
serialprintPGM(msg);
SERIAL_ECHOLNPGM("!");
_print_divider();
return true;
}
#endif
void PrintCounter::loadStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("loadStats"));
#endif
// Check if the EEPROM block is initialized
uint8_t value = 0;
persistentStore.access_start();
persistentStore.read_data(address, &value, sizeof(uint8_t));
if (value != 0x16)
initStats();
else
persistentStore.read_data(address + sizeof(uint8_t), (uint8_t*)&data, sizeof(printStatistics));
persistentStore.access_finish();
loaded = true;
#if HAS_SERVICE_INTERVALS
bool doBuzz = false;
#if SERVICE_INTERVAL_1 > 0
if (data.nextService1 == 0) doBuzz = _service_warn(PSTR(" " SERVICE_NAME_1));
#endif
#if SERVICE_INTERVAL_2 > 0
if (data.nextService2 == 0) doBuzz = _service_warn(PSTR(" " SERVICE_NAME_2));
#endif
#if SERVICE_INTERVAL_3 > 0
if (data.nextService3 == 0) doBuzz = _service_warn(PSTR(" " SERVICE_NAME_3));
#endif
#if HAS_BUZZER && SERVICE_WARNING_BUZZES > 0
if (doBuzz) for (int i = 0; i < SERVICE_WARNING_BUZZES; i++) BUZZ(200, 404);
#else
UNUSED(doBuzz);
#endif
#endif // HAS_SERVICE_INTERVALS
}
void PrintCounter::saveStats() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("saveStats"));
#endif
// Refuses to save data if object is not loaded
if (!isLoaded()) return;
// 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
}
#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));
}
#endif
void PrintCounter::showStats() {
char buffer[21];
SERIAL_ECHOPGM(STR_STATS);
SERIAL_ECHOLNPAIR(
"Prints: ", data.totalPrints,
", Finished: ", data.finishedPrints,
", Failed: ", data.totalPrints - data.finishedPrints
- ((isRunning() || isPaused()) ? 1 : 0) // Remove 1 from failures with an active counter
);
SERIAL_ECHOPGM(STR_STATS);
duration_t elapsed = data.printTime;
elapsed.toString(buffer);
SERIAL_ECHOPAIR("Total time: ", buffer);
#if ENABLED(DEBUG_PRINTCOUNTER)
SERIAL_ECHOPAIR(" (", data.printTime);
SERIAL_CHAR(')');
#endif
elapsed = data.longestPrint;
elapsed.toString(buffer);
SERIAL_ECHOPAIR(", Longest job: ", buffer);
#if ENABLED(DEBUG_PRINTCOUNTER)
SERIAL_ECHOPAIR(" (", data.longestPrint);
SERIAL_CHAR(')');
#endif
SERIAL_ECHOPAIR("\n" STR_STATS "Filament used: ", data.filamentUsed / 1000);
SERIAL_CHAR('m');
SERIAL_EOL();
#if SERVICE_INTERVAL_1 > 0
_service_when(buffer, PSTR(SERVICE_NAME_1), data.nextService1);
#endif
#if SERVICE_INTERVAL_2 > 0
_service_when(buffer, PSTR(SERVICE_NAME_2), data.nextService2);
#endif
#if SERVICE_INTERVAL_3 > 0
_service_when(buffer, PSTR(SERVICE_NAME_3), data.nextService3);
#endif
}
void PrintCounter::tick() {
if (!isRunning()) return;
millis_t now = millis();
static uint32_t update_next; // = 0
if (ELAPSED(now, update_next)) {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("tick"));
#endif
millis_t delta = deltaDuration();
data.printTime += delta;
#if SERVICE_INTERVAL_1 > 0
data.nextService1 -= _MIN(delta, data.nextService1);
#endif
#if SERVICE_INTERVAL_2 > 0
data.nextService2 -= _MIN(delta, data.nextService2);
#endif
#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();
}
}
// @Override
bool PrintCounter::start() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("start"));
#endif
bool paused = isPaused();
if (super::start()) {
if (!paused) {
data.totalPrints++;
lastDuration = 0;
}
return true;
}
return false;
}
// @Override
bool PrintCounter::stop() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("stop"));
#endif
if (super::stop()) {
data.finishedPrints++;
data.printTime += deltaDuration();
if (duration() > data.longestPrint)
data.longestPrint = duration();
saveStats();
return true;
}
else return false;
}
// @Override
void PrintCounter::reset() {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("stop"));
#endif
super::reset();
lastDuration = 0;
}
#if HAS_SERVICE_INTERVALS
void PrintCounter::resetServiceInterval(const int index) {
switch (index) {
#if SERVICE_INTERVAL_1 > 0
case 1: data.nextService1 = SERVICE_INTERVAL_SEC_1;
#endif
#if SERVICE_INTERVAL_2 > 0
case 2: data.nextService2 = SERVICE_INTERVAL_SEC_2;
#endif
#if SERVICE_INTERVAL_3 > 0
case 3: data.nextService3 = SERVICE_INTERVAL_SEC_3;
#endif
}
saveStats();
}
bool PrintCounter::needsService(const int index) {
switch (index) {
#if SERVICE_INTERVAL_1 > 0
case 1: return data.nextService1 == 0;
#endif
#if SERVICE_INTERVAL_2 > 0
case 2: return data.nextService2 == 0;
#endif
#if SERVICE_INTERVAL_3 > 0
case 3: return data.nextService3 == 0;
#endif
default: return false;
}
}
#endif // HAS_SERVICE_INTERVALS
#if ENABLED(DEBUG_PRINTCOUNTER)
void PrintCounter::debug(const char func[]) {
if (DEBUGGING(INFO)) {
SERIAL_ECHOPGM("PrintCounter::");
serialprintPGM(func);
SERIAL_ECHOLNPGM("()");
}
}
#endif
#endif // PRINTCOUNTER

207
Marlin/src/module/printcounter.h Executable file
View File

@@ -0,0 +1,207 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../libs/stopwatch.h"
#include "../libs/duration_t.h"
#include "../inc/MarlinConfig.h"
// 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
struct printStatistics { // 16 bytes
//const uint8_t magic; // Magic header, it will always be 0x16
uint16_t totalPrints; // Number of prints
uint16_t finishedPrints; // Number of complete prints
uint32_t printTime; // Accumulated printing time
uint32_t longestPrint; // Longest successful print job
float filamentUsed; // Accumulated filament consumed in mm
#if SERVICE_INTERVAL_1 > 0
uint32_t nextService1; // Service intervals (or placeholders)
#endif
#if SERVICE_INTERVAL_2 > 0
uint32_t nextService2;
#endif
#if SERVICE_INTERVAL_3 > 0
uint32_t nextService3;
#endif
};
class PrintCounter: public Stopwatch {
private:
typedef Stopwatch super;
#if USE_WIRED_EEPROM || defined(CPU_32_BIT)
typedef uint32_t eeprom_address_t;
#else
typedef uint16_t eeprom_address_t;
#endif
static printStatistics data;
/**
* @brief EEPROM address
* @details Defines the start offset address where the data is stored.
*/
static const eeprom_address_t address;
/**
* @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;
/**
* @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;
/**
* @brief Timestamp of the last call to deltaDuration()
* @details Store the timestamp of the last deltaDuration(), this is
* required due to the updateInterval cycle.
*/
static millis_t lastDuration;
/**
* @brief Stats were loaded from EEPROM
* @details If set to true it indicates if the statistical data was already
* loaded from the EEPROM.
*/
static bool loaded;
protected:
/**
* @brief dT since the last call
* @details Return the elapsed time in seconds since the last call, this is
* used internally for print statistics accounting is not intended to be a
* user callable function.
*/
static millis_t deltaDuration();
public:
/**
* @brief Initialize the print counter
*/
static inline void init() {
super::init();
loadStats();
}
/**
* @brief Check if Print Statistics has been loaded
* @details Return true if the statistical data has been loaded.
* @return bool
*/
FORCE_INLINE static bool isLoaded() { return loaded; }
/**
* @brief Increment the total filament used
* @details The total filament used counter will be incremented by "amount".
*
* @param amount The amount of filament used in mm
*/
static void incFilamentUsed(float const &amount);
/**
* @brief Reset the Print Statistics
* @details Reset the statistics to zero and saves them to EEPROM creating
* also the magic header.
*/
static void initStats();
/**
* @brief Load the Print Statistics
* @details Load the statistics from EEPROM
*/
static void loadStats();
/**
* @brief Save the Print Statistics
* @details Save the statistics to EEPROM
*/
static void saveStats();
/**
* @brief Serial output the Print Statistics
* @details This function may change in the future, for now it directly
* prints the statistical data to serial.
*/
static void showStats();
/**
* @brief Return the currently loaded statistics
* @details Return the raw data, in the same structure used internally
*/
static printStatistics getStats() { return data; }
/**
* @brief Loop function
* @details This function should be called at loop, it will take care of
* periodically save the statistical data to EEPROM and do time keeping.
*/
static void tick();
/**
* The following functions are being overridden
*/
static bool start();
static bool stop();
static void reset();
#if HAS_SERVICE_INTERVALS
static void resetServiceInterval(const int index);
static bool needsService(const int index);
#endif
#if ENABLED(DEBUG_PRINTCOUNTER)
/**
* @brief Print a debug message
* @details Print a simple debug message
*/
static void debug(const char func[]);
#endif
};
// Global Print Job Timer instance
#if ENABLED(PRINTCOUNTER)
extern PrintCounter print_job_timer;
#else
extern Stopwatch print_job_timer;
#endif

785
Marlin/src/module/probe.cpp Executable file
View File

@@ -0,0 +1,785 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* module/probe.cpp
*/
#include "../inc/MarlinConfig.h"
#if HAS_BED_PROBE
#include "probe.h"
#include "../libs/buzzer.h"
#include "motion.h"
#include "temperature.h"
#include "endstops.h"
#include "../gcode/gcode.h"
#include "../lcd/ultralcd.h"
#include "../MarlinCore.h" // for stop(), disable_e_steppers, wait_for_user
#if HAS_LEVELING
#include "../feature/bedlevel/bedlevel.h"
#endif
#if ENABLED(DELTA)
#include "delta.h"
#endif
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
#include "planner.h"
#endif
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
#include "../feature/backlash.h"
#endif
#if ENABLED(BLTOUCH)
#include "../feature/bltouch.h"
#endif
#if ENABLED(HOST_PROMPT_SUPPORT)
#include "../feature/host_actions.h" // for PROMPT_USER_CONTINUE
#endif
#if HAS_Z_SERVO_PROBE
#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"
#endif
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../core/debug_out.h"
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;
#endif
#if ENABLED(Z_PROBE_SLED)
#ifndef SLED_DOCKING_OFFSET
#define SLED_DOCKING_OFFSET 0
#endif
/**
* Method to dock/undock a sled designed by Charles Bell.
*
* stow[in] If false, move to MAX_X and engage the solenoid
* 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, ")");
// Dock sled a bit closer to ensure proper capturing
do_blocking_move_to_x(X_MAX_POS + SLED_DOCKING_OFFSET - ((stow) ? 1 : 0));
#if HAS_SOLENOID_1 && DISABLED(EXT_SOLENOID)
WRITE(SOL1_PIN, !stow); // switch solenoid
#endif
}
#elif ENABLED(TOUCH_MI_PROBE)
// Move to the magnet to unlock the probe
inline void run_deploy_moves_script() {
#ifndef TOUCH_MI_DEPLOY_XPOS
#define TOUCH_MI_DEPLOY_XPOS X_MIN_POS
#elif TOUCH_MI_DEPLOY_XPOS > X_MAX_BED
TemporaryGlobalEndstopsState unlock_x(false);
#endif
#if TOUCH_MI_DEPLOY_YPOS > Y_MAX_BED
TemporaryGlobalEndstopsState unlock_y(false);
#endif
#if ENABLED(TOUCH_MI_MANUAL_DEPLOY)
const screenFunc_t prev_screen = ui.currentScreen;
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();
ui.reset_status();
ui.goto_screen(prev_screen);
#elif defined(TOUCH_MI_DEPLOY_XPOS) && defined(TOUCH_MI_DEPLOY_YPOS)
do_blocking_move_to_xy(TOUCH_MI_DEPLOY_XPOS, TOUCH_MI_DEPLOY_YPOS);
#elif defined(TOUCH_MI_DEPLOY_XPOS)
do_blocking_move_to_x(TOUCH_MI_DEPLOY_XPOS);
#elif defined(TOUCH_MI_DEPLOY_YPOS)
do_blocking_move_to_y(TOUCH_MI_DEPLOY_YPOS);
#endif
}
// Move down to the bed to stow the probe
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));
}
#elif ENABLED(Z_PROBE_ALLEN_KEY)
inline void run_deploy_moves_script() {
#ifdef Z_PROBE_ALLEN_KEY_DEPLOY_1
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE 0.0
#endif
constexpr xyz_pos_t deploy_1 = Z_PROBE_ALLEN_KEY_DEPLOY_1;
do_blocking_move_to(deploy_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_DEPLOY_2
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE 0.0
#endif
constexpr xyz_pos_t deploy_2 = Z_PROBE_ALLEN_KEY_DEPLOY_2;
do_blocking_move_to(deploy_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_DEPLOY_3
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE 0.0
#endif
constexpr xyz_pos_t deploy_3 = Z_PROBE_ALLEN_KEY_DEPLOY_3;
do_blocking_move_to(deploy_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_DEPLOY_4
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE 0.0
#endif
constexpr xyz_pos_t deploy_4 = Z_PROBE_ALLEN_KEY_DEPLOY_4;
do_blocking_move_to(deploy_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_DEPLOY_5
#ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE
#define Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE 0.0
#endif
constexpr xyz_pos_t deploy_5 = Z_PROBE_ALLEN_KEY_DEPLOY_5;
do_blocking_move_to(deploy_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE));
#endif
}
inline void run_stow_moves_script() {
#ifdef Z_PROBE_ALLEN_KEY_STOW_1
#ifndef Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE 0.0
#endif
constexpr xyz_pos_t stow_1 = Z_PROBE_ALLEN_KEY_STOW_1;
do_blocking_move_to(stow_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_STOW_2
#ifndef Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE 0.0
#endif
constexpr xyz_pos_t stow_2 = Z_PROBE_ALLEN_KEY_STOW_2;
do_blocking_move_to(stow_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_STOW_3
#ifndef Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE 0.0
#endif
constexpr xyz_pos_t stow_3 = Z_PROBE_ALLEN_KEY_STOW_3;
do_blocking_move_to(stow_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_STOW_4
#ifndef Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE 0.0
#endif
constexpr xyz_pos_t stow_4 = Z_PROBE_ALLEN_KEY_STOW_4;
do_blocking_move_to(stow_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE));
#endif
#ifdef Z_PROBE_ALLEN_KEY_STOW_5
#ifndef Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE
#define Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE 0.0
#endif
constexpr xyz_pos_t stow_5 = Z_PROBE_ALLEN_KEY_STOW_5;
do_blocking_move_to(stow_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE));
#endif
}
#endif // Z_PROBE_ALLEN_KEY
#if QUIET_PROBING
void Probe::set_probing_paused(const bool p) {
#if ENABLED(PROBING_HEATERS_OFF)
thermalManager.pause(p);
#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
);
}
#endif // 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, ")");
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);
}
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;
#endif
BUZZ(100, 659);
BUZZ(100, 698);
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();
#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();
ui.reset_status();
} while(
#if ENABLED(PAUSE_PROBE_DEPLOY_WHEN_TRIGGERED)
true
#else
false
#endif
);
#endif // PAUSE_BEFORE_DEPLOY_STOW
#if ENABLED(SOLENOID_PROBE)
#if HAS_SOLENOID_1
WRITE(SOL1_PIN, deploy);
#endif
#elif ENABLED(Z_PROBE_SLED)
dock_sled(!deploy);
#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
#elif EITHER(TOUCH_MI_PROBE, Z_PROBE_ALLEN_KEY)
deploy ? run_deploy_moves_script() : run_stow_moves_script();
#elif ENABLED(RACK_AND_PINION_PROBE)
do_blocking_move_to_x(deploy ? Z_PROBE_DEPLOY_X : Z_PROBE_RETRACT_X);
#elif DISABLED(PAUSE_BEFORE_DEPLOY_STOW)
UNUSED(deploy);
#endif
}
/**
* Attempt to deploy or stow the probe
*
* Return TRUE if the probe could not be deployed/stowed
*/
bool Probe::set_deployed(const bool deploy) {
if (DEBUGGING(LEVELING)) {
DEBUG_POS("Probe::set_deployed", current_position);
DEBUG_ECHOLNPAIR("deploy: ", deploy);
}
if (endstops.z_probe_enabled == deploy) return false;
// Make room for probe to deploy (or stow)
// 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;
#else
constexpr bool deploy_stow_condition = 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)
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
)) {
SERIAL_ERROR_MSG(STR_STOP_UNHOMED);
stop();
return true;
}
#endif
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 (!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 (IsRunning()) {
SERIAL_ERROR_MSG("Z-Probe failed");
LCD_ALERTMESSAGEPGM_P(PSTR("Err: ZPROBE"));
}
stop();
return true;
}
#else
probe_specific_action(deploy);
#endif
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.
*
* @param z Z destination
* @param fr_mm_s Feedrate in mm/s
* @return true to indicate an error
*/
/**
* @brief Move down until the probe triggers or the low limit is reached
*
* @details Used by run_z_probe to get each bed Z height measurement.
* Sets current_position.z to the height where the probe triggered
* (according to the Z stepper count). The float Z is propagated
* back to the planner.position to preempt any rounding error.
*
* @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);
#if HAS_HEATED_BED && ENABLED(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
#endif
// 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);
#endif
stealth_states.z = tmc_enable_stallguard(stepperZ);
endstops.enable(true);
#endif
#if QUIET_PROBING
set_probing_paused(true);
#endif
// 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))
#else
TEST(endstops.trigger_state(),
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
Z_MIN
#else
Z_MIN_PROBE
#endif
)
#endif
;
#if QUIET_PROBING
set_probing_paused(false);
#endif
// 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);
#endif
tmc_disable_stallguard(stepperZ, stealth_states.z);
#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
// Clear endstop flags
endstops.hit_on_purpose();
// Get Z where the steppers were interrupted
set_current_from_steppers_for_axis(Z_AXIS);
// 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;
}
/**
* @brief Probe at the current XY (possibly more than once) to find the bed Z.
*
* @details Used by probe_at_point to get the bed Z height at the current XY.
* Leaves current_position.z at the height where the probe triggered.
*
* @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*/) {
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> Probe::run_z_probe", current_position);
// 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;
// Double-probing does a fast probe followed by a slow probe
#if TOTAL_PROBING == 2
// 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;
}
const float first_probe_z = current_position.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("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));
#elif Z_PROBE_SPEED_FAST != Z_PROBE_SPEED_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));
}
#endif
#ifdef EXTRA_PROBING
float probes[TOTAL_PROBING];
#endif
#if TOTAL_PROBING > 2
float probes_z_sum = 0;
for (
#if EXTRA_PROBING
uint8_t p = 0; p < TOTAL_PROBING; p++
#else
uint8_t p = TOTAL_PROBING; p--;
#endif
)
#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 ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
backlash.measure_with_probe();
#endif
const float z = current_position.z;
#if EXTRA_PROBING
// 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
for (int8_t m = p; --m >= i;) probes[m + 1] = probes[m]; // Shift items down after the insertion point
probes[i] = z; // Insert the new Z measurement
break; // Only one to insert. Done!
}
}
#elif TOTAL_PROBING > 2
probes_z_sum += z;
#else
UNUSED(z);
#endif
#if TOTAL_PROBING > 2
// Small Z raise after all but the last probe
if (p
#if EXTRA_PROBING
< TOTAL_PROBING - 1
#endif
) do_blocking_move_to_z(z + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
#endif
}
#if TOTAL_PROBING > 2
#if EXTRA_PROBING
// 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],
median = ((TOTAL_PROBING) & 1) ? middle : (middle + probes[PHALF + 1]) * 0.5f;
// Remove values farthest from the median
uint8_t min_avg_idx = 0, max_avg_idx = TOTAL_PROBING - 1;
for (uint8_t i = EXTRA_PROBING; i--;)
if (ABS(probes[max_avg_idx] - median) > ABS(probes[min_avg_idx] - median))
max_avg_idx--; else min_avg_idx++;
// Return the average value of all remaining probes.
LOOP_S_LE_N(i, min_avg_idx, max_avg_idx)
probes_z_sum += probes[i];
#endif
const float measured_z = probes_z_sum * RECIPROCAL(MULTIPLE_PROBING);
#elif TOTAL_PROBING == 2
const float z2 = current_position.z;
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR("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;
#else
// Return the single probe result
const float measured_z = current_position.z;
#endif
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< run_z_probe", current_position);
return measured_z;
}
/**
* - Move to the given XY
* - Deploy the probe, if not already deployed
* - Probe the bed, get the Z position
* - Depending on the 'stow' flag
* - Stow the probe, or
* - 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*/) {
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),
", ", probe_relative ? "probe" : "nozzle", "_relative)"
);
DEBUG_POS("", current_position);
}
#if BOTH(BLTOUCH, BLTOUCH_HS_MODE)
if (bltouch.triggered()) bltouch._reset();
#endif
// TODO: Adapt for SCARA, where the offset rotates
xyz_pos_t npos = { rx, ry };
if (probe_relative) { // The given position is in terms of the probe
if (!can_reach(npos)) {
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Position Not Reachable");
return NAN;
}
npos -= offset_xy; // Get the nozzle position
}
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);
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)
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);
}
}
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 (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("<<< Probe::probe_at_point");
return measured_z;
}
#if HAS_Z_SERVO_PROBE
void Probe::servo_probe_init() {
/**
* Set position of Z Servo Endstop
*
* The servo might be deployed and positioned too low to stow
* 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
#endif // HAS_BED_PROBE

216
Marlin/src/module/probe.h Executable file
View File

@@ -0,0 +1,216 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* module/probe.h - Move, deploy, enable, etc.
*/
#include "../inc/MarlinConfig.h"
#include "motion.h"
#if HAS_BED_PROBE
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_RAISE, // Raise to "between" clearance after run_z_probe
PROBE_PT_BIG_RAISE // Raise to big clearance after run_z_probe
};
#endif
class Probe {
public:
#if HAS_BED_PROBE
static xyz_pos_t offset;
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) {
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?
}
#else
FORCE_INLINE static bool can_reach(const float &rx, const float &ry) {
return position_is_reachable(rx, ry, MIN_PROBE_EDGE);
}
#endif
#else
/**
* Return whether the given position is within the bed, and whether the nozzle
* can reach the position required to put the probe at the given position.
*
* 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) {
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);
}
#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) {
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 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); }
#endif
FORCE_INLINE static bool can_reach(const xy_pos_t &pos) { return can_reach(pos.x, pos.y); }
FORCE_INLINE 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)
#else
can_reach(lf) && can_reach(rb)
#endif
);
}
// 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;
#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); }
#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
);
static inline float probe_radius() {
return printable_radius - _MAX(MIN_PROBE_EDGE, HYPOT(offset_xy.x, 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 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 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 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
);
}
#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]) {
#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);
#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);
#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());
#endif
#endif
}
#endif
#endif // HAS_BED_PROBE
#if HAS_Z_SERVO_PROBE
static void servo_probe_init();
#endif
#if QUIET_PROBING
static void set_probing_paused(const bool p);
#endif
private:
static bool probe_down_to_z(const float 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);
};
extern Probe probe;

164
Marlin/src/module/scara.cpp Executable file
View File

@@ -0,0 +1,164 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* scara.cpp
*/
#include "../inc/MarlinConfig.h"
#if IS_SCARA
#include "scara.h"
#include "motion.h"
#include "planner.h"
float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND;
void scara_set_axis_is_at_home(const AxisEnum axis) {
if (axis == Z_AXIS)
current_position.z = Z_HOME_POS;
else {
/**
* SCARA homes XY at the same time
*/
xyz_pos_t homeposition;
LOOP_XYZ(i) homeposition[i] = base_home_pos((AxisEnum)i);
#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
// SERIAL_ECHOPGM("Cartesian");
// SERIAL_ECHOLNPAIR_P(SP_X_LBL, current_position.x, SP_Y_LBL, current_position.y);
update_software_endstops(axis);
}
}
static constexpr xy_pos_t scara_offset = { SCARA_OFFSET_X, SCARA_OFFSET_Y };
/**
* 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) {
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;
cartes.set(a_cos + b_cos + scara_offset.x, // theta
a_sin + b_sin + scara_offset.y); // theta+phi
/*
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, ")");
//*/
}
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.
*/
float C2, S2, SK1, SK2, THETA, PSI;
// Translate SCARA to standard XY with scaling factor
const xy_pos_t spos = raw - scara_offset;
const float H2 = HYPOT2(spos.x, spos.y);
if (L1 == L2)
C2 = H2 / L1_2_2 - 1;
else
C2 = (H2 - (L1_2 + L2_2)) / (2.0f * L1 * L2);
S2 = SQRT(1.0f - sq(C2));
// Unrotated Arm1 plus rotated Arm2 gives the distance from Center to End
SK1 = L1 + L2 * C2;
// Rotated Arm2 gives the distance from Arm1 to Arm2
SK2 = L2 * S2;
// Angle of Arm1 is the difference between Center-to-End angle and the Center-to-Elbow
THETA = ATAN2(SK1, SK2) - ATAN2(spos.x, spos.y);
// Angle of Arm2
PSI = ATAN2(S2, C2);
delta.set(DEGREES(THETA), DEGREES(THETA + PSI), 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);
//*/
#else // MP_SCARA
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)),
THETA2 = THETA3 - ACOS((sq(c) + sq(L2) - sq(L1)) / (2.0f * c * L2));
delta.set(DEGREES(THETA1), DEGREES(THETA2), raw.z);
/*
DEBUG_POS("SCARA IK", raw);
DEBUG_POS("SCARA IK", delta);
SERIAL_ECHOLNPAIR(" SCARA (x,y) ", x, ",", y," Theta1=", THETA1, " Theta2=", THETA2);
//*/
#endif // MP_SCARA
}
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_EOL();
}
#endif // IS_SCARA

42
Marlin/src/module/scara.h Executable file
View File

@@ -0,0 +1,42 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* scara.h - SCARA-specific functions
*/
#include "../core/macros.h"
extern float delta_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));
void scara_set_axis_is_at_home(const AxisEnum axis);
void inverse_kinematics(const xyz_pos_t &raw);
void forward_kinematics_SCARA(const float &a, const float &b);
void scara_report_positions();

58
Marlin/src/module/servo.cpp Executable file
View File

@@ -0,0 +1,58 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* module/servo.cpp
*/
#include "../inc/MarlinConfig.h"
#if HAS_SERVOS
#include "servo.h"
HAL_SERVO_LIB servo[NUM_SERVOS];
#if ENABLED(EDITABLE_SERVO_ANGLES)
uint16_t servo_angles[NUM_SERVOS][2];
#endif
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.
#endif
#if NUM_SERVOS >= 2 && HAS_SERVO_1
servo[1].attach(SERVO1_PIN);
servo[1].detach();
#endif
#if NUM_SERVOS >= 3 && HAS_SERVO_2
servo[2].attach(SERVO2_PIN);
servo[2].detach();
#endif
#if NUM_SERVOS >= 4 && HAS_SERVO_3
servo[3].attach(SERVO3_PIN);
servo[3].detach();
#endif
}
#endif // HAS_SERVOS

115
Marlin/src/module/servo.h Executable file
View File

@@ -0,0 +1,115 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* module/servo.h
*/
#include "../inc/MarlinConfig.h"
#include "../HAL/shared/servo.h"
#if HAS_SERVO_ANGLES
#if ENABLED(SWITCHING_EXTRUDER)
// Switching extruder can have 2 or 4 angles
#if EXTRUDERS > 3
#define REQ_ANGLES 4
#else
#define REQ_ANGLES 2
#endif
constexpr uint16_t sase[] = SWITCHING_EXTRUDER_SERVO_ANGLES;
static_assert(COUNT(sase) == REQ_ANGLES, "SWITCHING_EXTRUDER_SERVO_ANGLES needs " STRINGIFY(REQ_ANGLES) " angles.");
#else
constexpr uint16_t sase[4] = { 0 };
#endif
#if ENABLED(SWITCHING_NOZZLE)
constexpr uint16_t sasn[] = SWITCHING_NOZZLE_SERVO_ANGLES;
static_assert(COUNT(sasn) == 2, "SWITCHING_NOZZLE_SERVO_ANGLES needs 2 angles.");
#else
constexpr uint16_t sasn[2] = { 0 };
#endif
#ifdef Z_PROBE_SERVO_NR
#if ENABLED(BLTOUCH)
#include "../feature/bltouch.h"
#undef Z_SERVO_ANGLES
#define Z_SERVO_ANGLES { BLTOUCH_DEPLOY, BLTOUCH_STOW }
#endif
constexpr uint16_t sazp[] = Z_SERVO_ANGLES;
static_assert(COUNT(sazp) == 2, "Z_SERVO_ANGLES needs 2 angles.");
#else
constexpr uint16_t sazp[2] = { 0 };
#endif
#ifndef SWITCHING_EXTRUDER_SERVO_NR
#define SWITCHING_EXTRUDER_SERVO_NR -1
#endif
#ifndef SWITCHING_EXTRUDER_E23_SERVO_NR
#define SWITCHING_EXTRUDER_E23_SERVO_NR -1
#endif
#ifndef SWITCHING_NOZZLE_SERVO_NR
#define SWITCHING_NOZZLE_SERVO_NR -1
#endif
#ifndef Z_PROBE_SERVO_NR
#define Z_PROBE_SERVO_NR -1
#endif
#define ASRC(N,I) ( \
N == SWITCHING_EXTRUDER_SERVO_NR ? sase[I] \
: N == SWITCHING_EXTRUDER_E23_SERVO_NR ? sase[I+2] \
: N == SWITCHING_NOZZLE_SERVO_NR ? sasn[I] \
: N == Z_PROBE_SERVO_NR ? sazp[I] \
: 0 )
#if ENABLED(EDITABLE_SERVO_ANGLES)
extern uint16_t servo_angles[NUM_SERVOS][2];
#define CONST_SERVO_ANGLES base_servo_angles
#else
#define CONST_SERVO_ANGLES servo_angles
#endif
constexpr uint16_t CONST_SERVO_ANGLES [NUM_SERVOS][2] = {
{ ASRC(0,0), ASRC(0,1) }
#if NUM_SERVOS > 1
, { ASRC(1,0), ASRC(1,1) }
#if NUM_SERVOS > 2
, { ASRC(2,0), ASRC(2,1) }
#if NUM_SERVOS > 3
, { ASRC(3,0), ASRC(3,1) }
#endif
#endif
#endif
};
#if HAS_Z_SERVO_PROBE
#define DEPLOY_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, servo_angles[Z_PROBE_SERVO_NR][0])
#define STOW_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, servo_angles[Z_PROBE_SERVO_NR][1])
#endif
#endif // HAS_SERVO_ANGLES
#define MOVE_SERVO(I, P) servo[I].move(P)
extern HAL_SERVO_LIB servo[NUM_SERVOS];
extern void servo_init();

View File

@@ -0,0 +1,168 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#if F_CPU == 16000000
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135},
{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32},
{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14},
{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8},
{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5},
{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3},
{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2},
{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2},
{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1},
{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1},
{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1},
{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1},
{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0},
{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1},
{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0},
{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1},
{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0},
{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0},
{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0},
{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1},
{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0},
{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0},
{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0},
{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0},
{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0},
{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0},
{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0},
{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1},
{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0},
{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0},
{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0},
{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}
};
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894},
{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657},
{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331},
{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198},
{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132},
{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94},
{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71},
{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55},
{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44},
{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36},
{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30},
{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25},
{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22},
{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18},
{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16},
{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15},
{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13},
{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11},
{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10},
{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9},
{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8},
{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8},
{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7},
{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7},
{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6},
{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5},
{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5},
{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5},
{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4},
{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4},
{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4},
{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}
};
#elif F_CPU == 20000000
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
{62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167},
{1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40},
{604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17},
{404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10},
{303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6},
{243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5},
{202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4},
{173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2},
{152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2},
{135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2},
{121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2},
{110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1},
{101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1},
{93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0},
{87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0},
{81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0},
{76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1},
{71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1},
{67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0},
{64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1},
{60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0},
{58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0},
{55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0},
{53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1},
{50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1},
{48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1},
{46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0},
{45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0},
{43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0},
{42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0},
{40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0},
{39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0},
};
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
{62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003},
{24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745},
{14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385},
{10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235},
{8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158},
{6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113},
{5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86},
{5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67},
{4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53},
{4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44},
{3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36},
{3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31},
{3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27},
{2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23},
{2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20},
{2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18},
{2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16},
{2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14},
{2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13},
{1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12},
{1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10},
{1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10},
{1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9},
{1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8},
{1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7},
{1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7},
{1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6},
{1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6},
{1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6},
{1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5},
{1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5},
{1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5},
};
#endif

3242
Marlin/src/module/stepper.cpp Executable file

File diff suppressed because it is too large Load Diff

566
Marlin/src/module/stepper.h Executable file
View File

@@ -0,0 +1,566 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
* Derived from Grbl
*
* Copyright (c) 2009-2011 Simen Svale Skogsrud
*
* Grbl 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.
*
* Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../inc/MarlinConfig.h"
#include "planner.h"
#include "stepper/indirection.h"
#ifdef __AVR__
#include "speed_lookuptable.h"
#endif
// Disable multiple steps per ISR
//#define DISABLE_MULTI_STEPPING
//
// Estimate the amount of time the Stepper ISR will take to execute
//
/**
* The method of calculating these cycle-constants is unclear.
* Most of them are no longer used directly for pulse timing, and exist
* only to estimate a maximum step rate based on the user's configuration.
* As 32-bit processors continue to diverge, maintaining cycle counts
* will become increasingly difficult and error-prone.
*/
#ifdef CPU_32_BIT
/**
* Duration of START_TIMED_PULSE
*
* ...as measured on an LPC1768 with a scope and converted to cycles.
* Not applicable to other 32-bit processors, but as long as others
* take longer, pulses will be longer. For example the SKR Pro
* (stm32f407zgt6) requires ~60 cyles.
*/
#define TIMER_READ_ADD_AND_STORE_CYCLES 34UL
// The base ISR takes 792 cycles
#define ISR_BASE_CYCLES 792UL
// Linear advance base time is 64 cycles
#if ENABLED(LIN_ADVANCE)
#define ISR_LA_BASE_CYCLES 64UL
#else
#define ISR_LA_BASE_CYCLES 0UL
#endif
// S curve interpolation adds 40 cycles
#if ENABLED(S_CURVE_ACCELERATION)
#define ISR_S_CURVE_CYCLES 40UL
#else
#define ISR_S_CURVE_CYCLES 0UL
#endif
// Stepper Loop base cycles
#define ISR_LOOP_BASE_CYCLES 4UL
// To start the step pulse, in the worst case takes
#define ISR_START_STEPPER_CYCLES 13UL
// And each stepper (start + stop pulse) takes in worst case
#define ISR_STEPPER_CYCLES 16UL
#else
// Cycles to perform actions in START_TIMED_PULSE
#define TIMER_READ_ADD_AND_STORE_CYCLES 13UL
// The base ISR takes 752 cycles
#define ISR_BASE_CYCLES 752UL
// Linear advance base time is 32 cycles
#if ENABLED(LIN_ADVANCE)
#define ISR_LA_BASE_CYCLES 32UL
#else
#define ISR_LA_BASE_CYCLES 0UL
#endif
// S curve interpolation adds 160 cycles
#if ENABLED(S_CURVE_ACCELERATION)
#define ISR_S_CURVE_CYCLES 160UL
#else
#define ISR_S_CURVE_CYCLES 0UL
#endif
// Stepper Loop base cycles
#define ISR_LOOP_BASE_CYCLES 32UL
// To start the step pulse, in the worst case takes
#define ISR_START_STEPPER_CYCLES 57UL
// And each stepper (start + stop pulse) takes in worst case
#define ISR_STEPPER_CYCLES 88UL
#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))
#else
#define ISR_MIXING_STEPPER_CYCLES 0UL
#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)
// 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))
#if MINIMUM_STEPPER_PULSE
#define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(uint32_t(MINIMUM_STEPPER_PULSE))
#elif HAS_DRIVER(LV8729)
#define MIN_STEPPER_PULSE_CYCLES uint32_t((((F_CPU) - 1) / 2000000) + 1) // 0.5µs, aka 500ns
#else
#define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(1UL)
#endif
// Calculate the minimum pulse times (high and low)
#if MINIMUM_STEPPER_PULSE && MAXIMUM_STEPPER_RATE
constexpr uint32_t _MIN_STEP_PERIOD_NS = 1000000000UL / MAXIMUM_STEPPER_RATE;
constexpr uint32_t _MIN_PULSE_HIGH_NS = 1000UL * MINIMUM_STEPPER_PULSE;
constexpr uint32_t _MIN_PULSE_LOW_NS = _MAX((_MIN_STEP_PERIOD_NS - _MIN(_MIN_STEP_PERIOD_NS, _MIN_PULSE_HIGH_NS)), _MIN_PULSE_HIGH_NS);
#elif MINIMUM_STEPPER_PULSE
// Assume 50% duty cycle
constexpr uint32_t _MIN_PULSE_HIGH_NS = 1000UL * MINIMUM_STEPPER_PULSE;
constexpr uint32_t _MIN_PULSE_LOW_NS = _MIN_PULSE_HIGH_NS;
#elif MAXIMUM_STEPPER_RATE
// Assume 50% duty cycle
constexpr uint32_t _MIN_PULSE_HIGH_NS = 500000000UL / MAXIMUM_STEPPER_RATE;
constexpr uint32_t _MIN_PULSE_LOW_NS = _MIN_PULSE_HIGH_NS;
#else
#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))
// If linear advance is enabled, then it is handled separately
#if ENABLED(LIN_ADVANCE)
// Estimate the minimum LA loop time
#if ENABLED(MIXING_EXTRUDER) // ToDo: ???
// HELP ME: What is what?
// Directions are set up for MIXING_STEPPERS - like before.
// Finding the right stepper may last up to MIXING_STEPPERS loops in get_next_stepper().
// These loops are a bit faster than advancing a bresenham counter.
// Always only one e-stepper is stepped.
#define MIN_ISR_LA_LOOP_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
#else
#define MIN_ISR_LA_LOOP_CYCLES ISR_STEPPER_CYCLES
#endif
// And the real loop time
#define ISR_LA_LOOP_CYCLES _MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LA_LOOP_CYCLES)
#else
#define ISR_LA_LOOP_CYCLES 0UL
#endif
// Now estimate the total ISR execution time in cycles given a step per ISR multiplier
#define ISR_EXECUTION_CYCLES(R) (((ISR_BASE_CYCLES + ISR_S_CURVE_CYCLES + (ISR_LOOP_CYCLES) * (R) + ISR_LA_BASE_CYCLES + ISR_LA_LOOP_CYCLES)) / (R))
// The maximum allowable stepping frequency when doing x128-x1 stepping (in Hz)
#define MAX_STEP_ISR_FREQUENCY_128X ((F_CPU) / ISR_EXECUTION_CYCLES(128))
#define MAX_STEP_ISR_FREQUENCY_64X ((F_CPU) / ISR_EXECUTION_CYCLES(64))
#define MAX_STEP_ISR_FREQUENCY_32X ((F_CPU) / ISR_EXECUTION_CYCLES(32))
#define MAX_STEP_ISR_FREQUENCY_16X ((F_CPU) / ISR_EXECUTION_CYCLES(16))
#define MAX_STEP_ISR_FREQUENCY_8X ((F_CPU) / ISR_EXECUTION_CYCLES(8))
#define MAX_STEP_ISR_FREQUENCY_4X ((F_CPU) / ISR_EXECUTION_CYCLES(4))
#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
//
// Stepper class definition
//
class Stepper {
public:
#if HAS_EXTRA_ENDSTOPS || ENABLED(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
#endif
static uint32_t motor_current_setting[3];
static bool initialized;
#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 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
#if ENABLED(Y_DUAL_ENDSTOPS)
static bool locked_Y_motor, locked_Y2_motor;
#endif
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
static bool locked_Z_motor, locked_Z2_motor
#if NUM_Z_STEPPER_DRIVERS >= 3
, locked_Z3_motor
#if NUM_Z_STEPPER_DRIVERS >= 4
, locked_Z4_motor
#endif
#endif
;
#endif
static uint32_t acceleration_time, deceleration_time; // time measured in Stepper Timer ticks
static uint8_t steps_per_isr; // Count of steps to perform per Stepper ISR call
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
#else
static constexpr uint8_t oversampling_factor = 0;
#endif
// Delta error variables for the Bresenham line tracer
static xyze_long_t delta_error;
static xyze_ulong_t advance_dividend;
static uint32_t advance_divisor,
step_events_completed, // The number of step events executed in the current block
accelerate_until, // The point from where we need to stop acceleration
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)
static uint8_t stepper_extruder;
#else
static constexpr uint8_t stepper_extruder = 0;
#endif
#if ENABLED(S_CURVE_ACCELERATION)
static int32_t bezier_A, // A coefficient in Bézier speed curve
bezier_B, // B coefficient in Bézier speed curve
bezier_C; // C coefficient in Bézier speed curve
static uint32_t bezier_F, // F coefficient in Bézier speed curve
bezier_AV; // AV coefficient in Bézier speed curve
#ifdef __AVR__
static bool A_negative; // If A coefficient was negative
#endif
static bool bezier_2nd_half; // If Bézier curve has been initialized or not
#endif
#if ENABLED(LIN_ADVANCE)
static constexpr uint32_t LA_ADV_NEVER = 0xFFFFFFFF;
static uint32_t nextAdvanceISR, LA_isr_rate;
static uint16_t LA_current_adv_steps, LA_final_adv_steps, LA_max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static int8_t LA_steps;
static bool LA_use_advance_lead;
#endif
#if ENABLED(INTEGRATED_BABYSTEPPING)
static constexpr uint32_t BABYSTEP_NEVER = 0xFFFFFFFF;
static uint32_t nextBabystepISR;
#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)
//
static xyze_int8_t count_direction;
public:
// Initialize stepper hardware
static void init();
// Interrupt Service Routine and phases
// The stepper subsystem goes to sleep when it runs out of things to execute.
// Call this to notify the subsystem that it is time to go to work.
static inline void wake_up() { ENABLE_STEPPER_DRIVER_INTERRUPT(); }
static inline bool is_awake() { return STEPPER_ISR_ENABLED(); }
static inline bool suspend() {
const bool awake = is_awake();
if (awake) DISABLE_STEPPER_DRIVER_INTERRUPT();
return awake;
}
// The ISR scheduler
static void isr();
// The stepper pulse ISR phase
static void pulse_phase_isr();
// The stepper block processing ISR phase
static uint32_t block_phase_isr();
#if ENABLED(LIN_ADVANCE)
// The Linear advance ISR phase
static uint32_t advance_isr();
FORCE_INLINE static void initiateLA() { nextAdvanceISR = 0; }
#endif
#if ENABLED(INTEGRATED_BABYSTEPPING)
// The Babystepping ISR phase
static uint32_t babystepping_isr();
FORCE_INLINE static void initiateBabystepping() {
if (nextBabystepISR == BABYSTEP_NEVER) {
nextBabystepISR = 0;
wake_up();
}
}
#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);
// 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_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();
// Quickly stop all steppers
FORCE_INLINE static void quick_stop() { abort_current_block = true; }
// The direction of a single motor
FORCE_INLINE static bool motor_direction(const AxisEnum axis) { return TEST(last_direction_bits, axis); }
// 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);
#endif
#if HAS_MICROSTEPS
static void microstep_ms(const uint8_t driver, const int8_t ms1, const int8_t ms2, const int8_t ms3);
static void microstep_mode(const uint8_t driver, const uint8_t stepping);
static void microstep_readings();
#endif
#if HAS_EXTRA_ENDSTOPS || ENABLED(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)
FORCE_INLINE static void set_x_lock(const bool state) { locked_X_motor = state; }
FORCE_INLINE static void set_x2_lock(const bool state) { locked_X2_motor = state; }
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
FORCE_INLINE static void set_y_lock(const bool state) { locked_Y_motor = state; }
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_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; }
#if NUM_Z_STEPPER_DRIVERS >= 4
FORCE_INLINE static void set_z4_lock(const bool state) { locked_Z4_motor = state; }
#endif
#endif
#endif
#if ENABLED(BABYSTEPPING)
static void do_babystep(const AxisEnum axis, const bool direction); // perform a short step with a single stepper motor, outside of any convention
#endif
#if HAS_MOTOR_CURRENT_PWM
static void refresh_motor_power();
#endif
// Set direction bits for all steppers
static void 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); }
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
step_rate <<= oversampling_factor;
uint8_t multistep = 1;
#if DISABLED(DISABLE_MULTI_STEPPING)
// The stepping frequency limits for each multistepping rate
static const uint32_t limit[] PROGMEM = {
( MAX_STEP_ISR_FREQUENCY_1X ),
( MAX_STEP_ISR_FREQUENCY_2X >> 1),
( MAX_STEP_ISR_FREQUENCY_4X >> 2),
( MAX_STEP_ISR_FREQUENCY_8X >> 3),
( MAX_STEP_ISR_FREQUENCY_16X >> 4),
( MAX_STEP_ISR_FREQUENCY_32X >> 5),
( MAX_STEP_ISR_FREQUENCY_64X >> 6),
(MAX_STEP_ISR_FREQUENCY_128X >> 7)
};
// Select the proper multistepping
uint8_t idx = 0;
while (idx < 7 && step_rate > (uint32_t)pgm_read_dword(&limit[idx])) {
step_rate >>= 1;
multistep <<= 1;
++idx;
};
#else
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
#endif
*loops = multistep;
#ifdef CPU_32_BIT
// 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;
NOLESS(step_rate, min_step_rate);
step_rate -= min_step_rate; // Correct for minimal speed
if (step_rate >= (8 * 256)) { // higher step rate
const uint8_t tmp_step_rate = (step_rate & 0x00FF);
const uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0],
gain = (uint16_t)pgm_read_word(table_address + 2);
timer = MultiU16X8toH16(tmp_step_rate, gain);
timer = (uint16_t)pgm_read_word(table_address) - timer;
}
else { // lower step rates
uint16_t table_address = (uint16_t)&speed_lookuptable_slow[0][0];
table_address += ((step_rate) >> 1) & 0xFFFC;
timer = (uint16_t)pgm_read_word(table_address)
- (((uint16_t)pgm_read_word(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
}
// (there is no need to limit the timer value here. All limits have been
// applied above, and AVR is able to keep up at 30khz Stepping ISR rate)
#endif
return timer;
}
#if ENABLED(S_CURVE_ACCELERATION)
static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av);
static int32_t _eval_bezier_curve(const uint32_t curr_step);
#endif
#if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
static void digipot_init();
#endif
#if HAS_MICROSTEPS
static void microstep_init();
#endif
};
extern Stepper stepper;

View File

@@ -0,0 +1,225 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* stepper/L64xx.cpp
* Stepper driver indirection for L64XX drivers
*/
#include "../../inc/MarlinConfig.h"
#if HAS_L64XX
#include "L64xx.h"
#if AXIS_IS_L64XX(X)
L64XX_CLASS(X) stepperX(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(X2)
L64XX_CLASS(X2) stepperX2(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Y)
L64XX_CLASS(Y) stepperY(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Y2)
L64XX_CLASS(Y2) stepperY2(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Z)
L64XX_CLASS(Z) stepperZ(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Z2)
L64XX_CLASS(Z2) stepperZ2(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Z3)
L64XX_CLASS(Z3) stepperZ3(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(Z4)
L64XX_CLASS(Z4) stepperZ4(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E0)
L64XX_CLASS(E0) stepperE0(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E1)
L64XX_CLASS(E1) stepperE1(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E2)
L64XX_CLASS(E2) stepperE2(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E3)
L64XX_CLASS(E3) stepperE3(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E4)
L64XX_CLASS(E4) stepperE4(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E5)
L64XX_CLASS(E5) stepperE5(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E6)
L64XX_CLASS(E6) stepperE6(L6470_CHAIN_SS_PIN);
#endif
#if AXIS_IS_L64XX(E7)
L64XX_CLASS(E7) stepperE7(L6470_CHAIN_SS_PIN);
#endif
// Not using L64XX class init method because it
// briefly sends power to the steppers
inline void L6470_init_chip(L64XX &st, const int ms, const int oc, const int sc, const int mv, const int slew_rate) {
st.set_handlers(L64xxManager.spi_init, L64xxManager.transfer_single, L64xxManager.transfer_chain); // specify which external SPI routines to use
switch (st.L6470_status_layout) {
case L6470_STATUS_LAYOUT: {
st.resetDev();
st.softFree();
st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
st.SetParam(L6470_KVAL_RUN, 0xFF);
st.SetParam(L6470_KVAL_ACC, 0xFF);
st.SetParam(L6470_KVAL_DEC, 0xFF);
st.setMicroSteps(ms);
st.setOverCurrent(oc);
st.setStallCurrent(sc);
st.SetParam(L6470_KVAL_HOLD, mv);
st.SetParam(L6470_ABS_POS, 0);
uint32_t config_temp = st.GetParam(st.L64XX_CONFIG);
config_temp &= ~CONFIG_POW_SR;
switch (slew_rate) {
case 0: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_75V_us); break;
default:
case 1: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_110V_us); break;
case 3:
case 2: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_260V_us); break;
}
st.getStatus();
st.getStatus();
break;
}
case L6474_STATUS_LAYOUT: {
st.free();
//st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
//st.SetParam(L6474_TVAL, 0xFF);
st.setMicroSteps(ms);
st.setOverCurrent(oc);
st.setTVALCurrent(sc);
st.SetParam(L6470_ABS_POS, 0);
uint32_t config_temp = st.GetParam(st.L64XX_CONFIG);
config_temp &= ~CONFIG_POW_SR & ~CONFIG_EN_TQREG; // clear out slew rate and set current to be controlled by TVAL register
switch (slew_rate) {
case 0: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_75V_us); break;
default:
case 1: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_110V_us); break;
case 3:
case 2: st.SetParam(st.L64XX_CONFIG, config_temp | CONFIG_SR_260V_us); break;
//case 0: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_75V_us); break;
//default:
//case 1: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_110V_us); break;
//case 3:
//case 2: st.SetParam(st.L64XX_CONFIG, 0x2E88 | CONFIG_EN_TQREG | CONFIG_SR_260V_us); break;
//case 0: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
//default:
//case 1: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
//case 3:
//case 2: st.SetParam(st.L64XX_CONFIG, 0x2E88 ); break;
}
st.getStatus();
st.getStatus();
break;
}
case L6480_STATUS_LAYOUT: {
st.resetDev();
st.softFree();
st.SetParam(st.L64XX_CONFIG, CONFIG_PWM_DIV_1 | CONFIG_PWM_MUL_2 | CONFIG_OC_SD_DISABLE | CONFIG_VS_COMP_DISABLE | CONFIG_SW_HARD_STOP | CONFIG_INT_16MHZ);
st.SetParam(L6470_KVAL_RUN, 0xFF);
st.SetParam(L6470_KVAL_ACC, 0xFF);
st.SetParam(L6470_KVAL_DEC, 0xFF);
st.setMicroSteps(ms);
st.setOverCurrent(oc);
st.setStallCurrent(sc);
st.SetParam(+-L6470_KVAL_HOLD, mv);
st.SetParam(L6470_ABS_POS, 0);
st.SetParam(st.L64XX_CONFIG,(st.GetParam(st.L64XX_CONFIG) | PWR_VCC_7_5V));
st.getStatus(); // must clear out status bits before can set slew rate
st.getStatus();
switch (slew_rate) {
case 0: st.SetParam(L6470_GATECFG1, CONFIG1_SR_220V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_220V_us); break;
default:
case 1: st.SetParam(L6470_GATECFG1, CONFIG1_SR_400V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_400V_us); break;
case 2: st.SetParam(L6470_GATECFG1, CONFIG1_SR_520V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_520V_us); break;
case 3: st.SetParam(L6470_GATECFG1, CONFIG1_SR_980V_us); st.SetParam(L6470_GATECFG2, CONFIG2_SR_980V_us); break;
}
break;
}
}
}
#define L6470_INIT_CHIP(Q) L6470_init_chip(stepper##Q, Q##_MICROSTEPS, Q##_OVERCURRENT, Q##_STALLCURRENT, Q##_MAX_VOLTAGE, Q##_SLEW_RATE)
void L64XX_Marlin::init_to_defaults() {
#if AXIS_IS_L64XX(X)
L6470_INIT_CHIP(X);
#endif
#if AXIS_IS_L64XX(X2)
L6470_INIT_CHIP(X2);
#endif
#if AXIS_IS_L64XX(Y)
L6470_INIT_CHIP(Y);
#endif
#if AXIS_IS_L64XX(Y2)
L6470_INIT_CHIP(Y2);
#endif
#if AXIS_IS_L64XX(Z)
L6470_INIT_CHIP(Z);
#endif
#if AXIS_IS_L64XX(Z2)
L6470_INIT_CHIP(Z2);
#endif
#if AXIS_IS_L64XX(Z3)
L6470_INIT_CHIP(Z3);
#endif
#if AXIS_IS_L64XX(E0)
L6470_INIT_CHIP(E0);
#endif
#if AXIS_IS_L64XX(E1)
L6470_INIT_CHIP(E1);
#endif
#if AXIS_IS_L64XX(E2)
L6470_INIT_CHIP(E2);
#endif
#if AXIS_IS_L64XX(E3)
L6470_INIT_CHIP(E3);
#endif
#if AXIS_IS_L64XX(E4)
L6470_INIT_CHIP(E4);
#endif
#if AXIS_IS_L64XX(E5)
L6470_INIT_CHIP(E5);
#endif
#if AXIS_IS_L64XX(E6)
L6470_INIT_CHIP(E6);
#endif
#if AXIS_IS_L64XX(E7)
L6470_INIT_CHIP(E7);
#endif
}
#endif // HAS_L64XX

364
Marlin/src/module/stepper/L64xx.h Executable file
View File

@@ -0,0 +1,364 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* stepper/L64xx.h
* Stepper driver indirection for L64XX drivers
*/
#include "../../inc/MarlinConfig.h"
#include "../../libs/L64XX/L64XX_Marlin.h"
// Convert option names to L64XX classes
#define CLASS_L6470 L6470
#define CLASS_L6474 L6474
#define CLASS_POWERSTEP01 powerSTEP01
#define __L64XX_CLASS(TYPE) CLASS_##TYPE
#define _L64XX_CLASS(TYPE) __L64XX_CLASS(TYPE)
#define L64XX_CLASS(ST) _L64XX_CLASS(ST##_DRIVER_TYPE)
#define L6474_DIR_WRITE(A,STATE) do{ L64xxManager.dir_commands[A] = dSPIN_L6474_ENABLE; WRITE(A##_DIR_PIN, STATE); }while(0)
#define L64XX_DIR_WRITE(A,STATE) do{ L64xxManager.dir_commands[A] = (STATE) ? dSPIN_STEP_CLOCK_REV : dSPIN_STEP_CLOCK_FWD; }while(0)
// X Stepper
#if AXIS_IS_L64XX(X)
extern L64XX_CLASS(X) stepperX;
#define X_ENABLE_INIT() NOOP
#define X_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperX.free())
#define X_ENABLE_READ() (stepperX.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_X(L6474)
#define X_DIR_INIT() SET_OUTPUT(X_DIR_PIN)
#define X_DIR_WRITE(STATE) L6474_DIR_WRITE(X, STATE)
#define X_DIR_READ() READ(X_DIR_PIN)
#else
#define X_DIR_INIT() NOOP
#define X_DIR_WRITE(STATE) L64XX_DIR_WRITE(X, STATE)
#define X_DIR_READ() (stepper##X.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_X(L6470)
#define DISABLE_STEPPER_X() stepperX.free()
#endif
#endif
#endif
// Y Stepper
#if AXIS_IS_L64XX(Y)
extern L64XX_CLASS(Y) stepperY;
#define Y_ENABLE_INIT() NOOP
#define Y_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperY.free())
#define Y_ENABLE_READ() (stepperY.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Y(L6474)
#define Y_DIR_INIT() SET_OUTPUT(Y_DIR_PIN)
#define Y_DIR_WRITE(STATE) L6474_DIR_WRITE(Y, STATE)
#define Y_DIR_READ() READ(Y_DIR_PIN)
#else
#define Y_DIR_INIT() NOOP
#define Y_DIR_WRITE(STATE) L64XX_DIR_WRITE(Y, STATE)
#define Y_DIR_READ() (stepper##Y.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_Y(L6470)
#define DISABLE_STEPPER_Y() stepperY.free()
#endif
#endif
#endif
// Z Stepper
#if AXIS_IS_L64XX(Z)
extern L64XX_CLASS(Z) stepperZ;
#define Z_ENABLE_INIT() NOOP
#define Z_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ.free())
#define Z_ENABLE_READ() (stepperZ.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Z(L6474)
#define Z_DIR_INIT() SET_OUTPUT(Z_DIR_PIN)
#define Z_DIR_WRITE(STATE) L6474_DIR_WRITE(Z, STATE)
#define Z_DIR_READ() READ(Z_DIR_PIN)
#else
#define Z_DIR_INIT() NOOP
#define Z_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z, STATE)
#define Z_DIR_READ() (stepper##Z.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_Z(L6470)
#define DISABLE_STEPPER_Z() stepperZ.free()
#endif
#endif
#endif
// X2 Stepper
#if HAS_X2_ENABLE && AXIS_IS_L64XX(X2)
extern L64XX_CLASS(X2) stepperX2;
#define X2_ENABLE_INIT() NOOP
#define X2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperX2.free())
#define X2_ENABLE_READ() (stepperX2.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_X2(L6474)
#define X2_DIR_INIT() SET_OUTPUT(X2_DIR_PIN)
#define X2_DIR_WRITE(STATE) L6474_DIR_WRITE(X2, STATE)
#define X2_DIR_READ() READ(X2_DIR_PIN)
#else
#define X2_DIR_INIT() NOOP
#define X2_DIR_WRITE(STATE) L64XX_DIR_WRITE(X2, STATE)
#define X2_DIR_READ() (stepper##X2.getStatus() & STATUS_DIR);
#endif
#endif
#if AXIS_DRIVER_TYPE_X2(L6470)
#define DISABLE_STEPPER_X2() stepperX2.free()
#endif
// Y2 Stepper
#if HAS_Y2_ENABLE && AXIS_IS_L64XX(Y2)
extern L64XX_CLASS(Y2) stepperY2;
#define Y2_ENABLE_INIT() NOOP
#define Y2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperY2.free())
#define Y2_ENABLE_READ() (stepperY2.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Y2(L6474)
#define Y2_DIR_INIT() SET_OUTPUT(Y2_DIR_PIN)
#define Y2_DIR_WRITE(STATE) L6474_DIR_WRITE(Y2, STATE)
#define Y2_DIR_READ() READ(Y2_DIR_PIN)
#else
#define Y2_DIR_INIT() NOOP
#define Y2_DIR_WRITE(STATE) L64XX_DIR_WRITE(Y2, STATE)
#define Y2_DIR_READ() (stepper##Y2.getStatus() & STATUS_DIR);
#endif
#endif
#if AXIS_DRIVER_TYPE_Y2(L6470)
#define DISABLE_STEPPER_Y2() stepperY2.free()
#endif
// Z2 Stepper
#if HAS_Z2_ENABLE && AXIS_IS_L64XX(Z2)
extern L64XX_CLASS(Z2) stepperZ2;
#define Z2_ENABLE_INIT() NOOP
#define Z2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ2.free())
#define Z2_ENABLE_READ() (stepperZ2.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Z2(L6474)
#define Z2_DIR_INIT() SET_OUTPUT(Z2_DIR_PIN)
#define Z2_DIR_WRITE(STATE) L6474_DIR_WRITE(Z2, STATE)
#define Z2_DIR_READ() READ(Z2_DIR_PIN)
#else
#define Z2_DIR_INIT() NOOP
#define Z2_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z2, STATE)
#define Z2_DIR_READ() (stepper##Z2.getStatus() & STATUS_DIR);
#endif
#endif
#if AXIS_DRIVER_TYPE_Z2(L6470)
#define DISABLE_STEPPER_Z2() stepperZ2.free()
#endif
// Z3 Stepper
#if HAS_Z3_ENABLE && AXIS_IS_L64XX(Z3)
extern L64XX_CLASS(Z3) stepperZ3;
#define Z3_ENABLE_INIT() NOOP
#define Z3_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperZ3.free())
#define Z3_ENABLE_READ() (stepperZ3.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Z3(L6474)
#define Z3_DIR_INIT() SET_OUTPUT(Z3_DIR_PIN)
#define Z3_DIR_WRITE(STATE) L6474_DIR_WRITE(Z3, STATE)
#define Z3_DIR_READ() READ(Z3_DIR_PIN)
#else
#define Z3_DIR_INIT() NOOP
#define Z3_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z3, STATE)
#define Z3_DIR_READ() (stepper##Z3.getStatus() & STATUS_DIR);
#endif
#endif
#if AXIS_DRIVER_TYPE_Z3(L6470)
#define DISABLE_STEPPER_Z3() stepperZ3.free()
#endif
// Z4 Stepper
#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_READ() (stepperZ4.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_Z4(L6474)
#define Z4_DIR_INIT() SET_OUTPUT(Z4_DIR_PIN)
#define Z4_DIR_WRITE(STATE) L6474_DIR_WRITE(Z4, STATE)
#define Z4_DIR_READ() READ(Z4_DIR_PIN)
#else
#define Z4_DIR_INIT() NOOP
#define Z4_DIR_WRITE(STATE) L64XX_DIR_WRITE(Z4, STATE)
#define Z4_DIR_READ() (stepper##Z4.getStatus() & STATUS_DIR);
#endif
#endif
#if AXIS_DRIVER_TYPE_Z4(L6470)
#define DISABLE_STEPPER_Z4() stepperZ4.free()
#endif
// E0 Stepper
#if AXIS_IS_L64XX(E0)
extern L64XX_CLASS(E0) stepperE0;
#define E0_ENABLE_INIT() NOOP
#define E0_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE0.free())
#define E0_ENABLE_READ() (stepperE0.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E0(L6474)
#define E0_DIR_INIT() SET_OUTPUT(E0_DIR_PIN)
#define E0_DIR_WRITE(STATE) L6474_DIR_WRITE(E0, STATE)
#define E0_DIR_READ() READ(E0_DIR_PIN)
#else
#define E0_DIR_INIT() NOOP
#define E0_DIR_WRITE(STATE) L64XX_DIR_WRITE(E0, STATE)
#define E0_DIR_READ() (stepper##E0.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E0(L6470)
#define DISABLE_STEPPER_E0() do{ stepperE0.free(); CBI(axis_known_position, E_AXIS); }while(0)
#endif
#endif
#endif
// E1 Stepper
#if AXIS_IS_L64XX(E1)
extern L64XX_CLASS(E1) stepperE1;
#define E1_ENABLE_INIT() NOOP
#define E1_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE1.free())
#define E1_ENABLE_READ() (stepperE1.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E1(L6474)
#define E1_DIR_INIT() SET_OUTPUT(E1_DIR_PIN)
#define E1_DIR_WRITE(STATE) L6474_DIR_WRITE(E1, STATE)
#define E1_DIR_READ() READ(E1_DIR_PIN)
#else
#define E1_DIR_INIT() NOOP
#define E1_DIR_WRITE(STATE) L64XX_DIR_WRITE(E1, STATE)
#define E1_DIR_READ() (stepper##E1.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E1(L6470)
#define DISABLE_STEPPER_E1() do{ stepperE1.free(); CBI(axis_known_position, E_AXIS); }while(0)
#endif
#endif
#endif
// E2 Stepper
#if AXIS_IS_L64XX(E2)
extern L64XX_CLASS(E2) stepperE2;
#define E2_ENABLE_INIT() NOOP
#define E2_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE2.free())
#define E2_ENABLE_READ() (stepperE2.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E2(L6474)
#define E2_DIR_INIT() SET_OUTPUT(E2_DIR_PIN)
#define E2_DIR_WRITE(STATE) L6474_DIR_WRITE(E2, STATE)
#define E2_DIR_READ() READ(E2_DIR_PIN)
#else
#define E2_DIR_INIT() NOOP
#define E2_DIR_WRITE(STATE) L64XX_DIR_WRITE(E2, STATE)
#define E2_DIR_READ() (stepper##E2.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E2(L6470)
#define DISABLE_STEPPER_E2() do{ stepperE2.free(); CBI(axis_known_position, E_AXIS); }while(0)
#endif
#endif
#endif
// E3 Stepper
#if AXIS_IS_L64XX(E3)
extern L64XX_CLASS(E3) stepperE3;
#define E3_ENABLE_INIT() NOOP
#define E3_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE3.free())
#define E3_ENABLE_READ() (stepperE3.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E3(L6474)
#define E3_DIR_INIT() SET_OUTPUT(E3_DIR_PIN)
#define E3_DIR_WRITE(STATE) L6474_DIR_WRITE(E3, STATE)
#define E3_DIR_READ() READ(E3_DIR_PIN)
#else
#define E3_DIR_INIT() NOOP
#define E3_DIR_WRITE(STATE) L64XX_DIR_WRITE(E3, STATE)
#define E3_DIR_READ() (stepper##E3.getStatus() & STATUS_DIR);
#endif
#endif
// E4 Stepper
#if AXIS_IS_L64XX(E4)
extern L64XX_CLASS(E4) stepperE4;
#define E4_ENABLE_INIT() NOOP
#define E4_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE4.free())
#define E4_ENABLE_READ() (stepperE4.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E4(L6474)
#define E4_DIR_INIT() SET_OUTPUT(E4_DIR_PIN)
#define E4_DIR_WRITE(STATE) L6474_DIR_WRITE(E4, STATE)
#define E4_DIR_READ() READ(E4_DIR_PIN)
#else
#define E4_DIR_INIT() NOOP
#define E4_DIR_WRITE(STATE) L64XX_DIR_WRITE(E4, STATE)
#define E4_DIR_READ() (stepper##E4.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E4(L6470)
#define DISABLE_STEPPER_E4() do{ stepperE4.free(); CBI(axis_known_position, E_AXIS); }while(0)
#endif
#endif
#endif
// E5 Stepper
#if AXIS_IS_L64XX(E5)
extern L64XX_CLASS(E5) stepperE5;
#define E5_ENABLE_INIT() NOOP
#define E5_ENABLE_WRITE(STATE) (STATE ? NOOP : stepperE5.free())
#define E5_ENABLE_READ() (stepperE5.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E5(L6474)
#define E5_DIR_INIT() SET_OUTPUT(E5_DIR_PIN)
#define E5_DIR_WRITE(STATE) L6474_DIR_WRITE(E5, STATE)
#define E5_DIR_READ() READ(E5_DIR_PIN)
#else
#define E5_DIR_INIT() NOOP
#define E5_DIR_WRITE(STATE) L64XX_DIR_WRITE(E5, STATE)
#define E5_DIR_READ() (stepper##E5.getStatus() & STATUS_DIR);
#if AXIS_DRIVER_TYPE_E5(L6470)
#define DISABLE_STEPPER_E5() do{ stepperE5.free(); CBI(axis_known_position, E_AXIS); }while(0)
#endif
#endif
#endif
// E6 Stepper
#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_READ() (stepperE6.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E6(L6474)
#define E6_DIR_INIT() SET_OUTPUT(E6_DIR_PIN)
#define E6_DIR_WRITE(STATE) L6474_DIR_WRITE(E6, STATE)
#define E6_DIR_READ() READ(E6_DIR_PIN)
#else
#define E6_DIR_INIT() NOOP
#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)
#endif
#endif
#endif
// E7 Stepper
#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_READ() (stepperE7.getStatus() & STATUS_HIZ)
#if AXIS_DRIVER_TYPE_E7(L6474)
#define E7_DIR_INIT() SET_OUTPUT(E7_DIR_PIN)
#define E7_DIR_WRITE(STATE) L6474_DIR_WRITE(E7, STATE)
#define E7_DIR_READ() READ(E7_DIR_PIN)
#else
#define E7_DIR_INIT() NOOP
#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)
#endif
#endif
#endif

View File

@@ -0,0 +1,144 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* stepper/TMC26X.cpp
* Stepper driver indirection for TMC26X drivers
*/
#include "../../inc/MarlinConfig.h"
//
// TMC26X Driver objects and inits
//
#if HAS_DRIVER(TMC26X)
#include "TMC26X.h"
#define _TMC26X_DEFINE(ST) TMC26XStepper stepper##ST(200, ST##_CS_PIN, ST##_STEP_PIN, ST##_DIR_PIN, ST##_MAX_CURRENT, ST##_SENSE_RESISTOR)
#if AXIS_DRIVER_TYPE_X(TMC26X)
_TMC26X_DEFINE(X);
#endif
#if AXIS_DRIVER_TYPE_X2(TMC26X)
_TMC26X_DEFINE(X2);
#endif
#if AXIS_DRIVER_TYPE_Y(TMC26X)
_TMC26X_DEFINE(Y);
#endif
#if AXIS_DRIVER_TYPE_Y2(TMC26X)
_TMC26X_DEFINE(Y2);
#endif
#if AXIS_DRIVER_TYPE_Z(TMC26X)
_TMC26X_DEFINE(Z);
#endif
#if AXIS_DRIVER_TYPE_Z2(TMC26X)
_TMC26X_DEFINE(Z2);
#endif
#if AXIS_DRIVER_TYPE_Z3(TMC26X)
_TMC26X_DEFINE(Z3);
#endif
#if AXIS_DRIVER_TYPE_Z4(TMC26X)
_TMC26X_DEFINE(Z4);
#endif
#if AXIS_DRIVER_TYPE_E0(TMC26X)
_TMC26X_DEFINE(E0);
#endif
#if AXIS_DRIVER_TYPE_E1(TMC26X)
_TMC26X_DEFINE(E1);
#endif
#if AXIS_DRIVER_TYPE_E2(TMC26X)
_TMC26X_DEFINE(E2);
#endif
#if AXIS_DRIVER_TYPE_E3(TMC26X)
_TMC26X_DEFINE(E3);
#endif
#if AXIS_DRIVER_TYPE_E4(TMC26X)
_TMC26X_DEFINE(E4);
#endif
#if AXIS_DRIVER_TYPE_E5(TMC26X)
_TMC26X_DEFINE(E5);
#endif
#if AXIS_DRIVER_TYPE_E6(TMC26X)
_TMC26X_DEFINE(E6);
#endif
#if AXIS_DRIVER_TYPE_E7(TMC26X)
_TMC26X_DEFINE(E7);
#endif
#define _TMC26X_INIT(A) do{ \
stepper##A.setMicrosteps(A##_MICROSTEPS); \
stepper##A.start(); \
}while(0)
void tmc26x_init_to_defaults() {
#if AXIS_DRIVER_TYPE_X(TMC26X)
_TMC26X_INIT(X);
#endif
#if AXIS_DRIVER_TYPE_X2(TMC26X)
_TMC26X_INIT(X2);
#endif
#if AXIS_DRIVER_TYPE_Y(TMC26X)
_TMC26X_INIT(Y);
#endif
#if AXIS_DRIVER_TYPE_Y2(TMC26X)
_TMC26X_INIT(Y2);
#endif
#if AXIS_DRIVER_TYPE_Z(TMC26X)
_TMC26X_INIT(Z);
#endif
#if AXIS_DRIVER_TYPE_Z2(TMC26X)
_TMC26X_INIT(Z2);
#endif
#if AXIS_DRIVER_TYPE_Z3(TMC26X)
_TMC26X_INIT(Z3);
#endif
#if AXIS_DRIVER_TYPE_Z4(TMC26X)
_TMC26X_INIT(Z4);
#endif
#if AXIS_DRIVER_TYPE_E0(TMC26X)
_TMC26X_INIT(E0);
#endif
#if AXIS_DRIVER_TYPE_E1(TMC26X)
_TMC26X_INIT(E1);
#endif
#if AXIS_DRIVER_TYPE_E2(TMC26X)
_TMC26X_INIT(E2);
#endif
#if AXIS_DRIVER_TYPE_E3(TMC26X)
_TMC26X_INIT(E3);
#endif
#if AXIS_DRIVER_TYPE_E4(TMC26X)
_TMC26X_INIT(E4);
#endif
#if AXIS_DRIVER_TYPE_E5(TMC26X)
_TMC26X_INIT(E5);
#endif
#if AXIS_DRIVER_TYPE_E6(TMC26X)
_TMC26X_INIT(E6);
#endif
#if AXIS_DRIVER_TYPE_E7(TMC26X)
_TMC26X_INIT(E7);
#endif
}
#endif // TMC26X

View File

@@ -0,0 +1,168 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* stepper/TMC26X.h
* Stepper driver indirection for TMC26X drivers
*/
#include "../../inc/MarlinConfig.h"
// 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
void tmc26x_init_to_defaults();
// X Stepper
#if AXIS_DRIVER_TYPE_X(TMC26X)
extern TMC26XStepper stepperX;
#define X_ENABLE_INIT() NOOP
#define X_ENABLE_WRITE(STATE) stepperX.setEnabled(STATE)
#define X_ENABLE_READ() stepperX.isEnabled()
#endif
// Y Stepper
#if AXIS_DRIVER_TYPE_Y(TMC26X)
extern TMC26XStepper stepperY;
#define Y_ENABLE_INIT() NOOP
#define Y_ENABLE_WRITE(STATE) stepperY.setEnabled(STATE)
#define Y_ENABLE_READ() stepperY.isEnabled()
#endif
// Z Stepper
#if AXIS_DRIVER_TYPE_Z(TMC26X)
extern TMC26XStepper stepperZ;
#define Z_ENABLE_INIT() NOOP
#define Z_ENABLE_WRITE(STATE) stepperZ.setEnabled(STATE)
#define Z_ENABLE_READ() stepperZ.isEnabled()
#endif
// X2 Stepper
#if HAS_X2_ENABLE && AXIS_DRIVER_TYPE_X2(TMC26X)
extern TMC26XStepper stepperX2;
#define X2_ENABLE_INIT() NOOP
#define X2_ENABLE_WRITE(STATE) stepperX2.setEnabled(STATE)
#define X2_ENABLE_READ() stepperX2.isEnabled()
#endif
// Y2 Stepper
#if HAS_Y2_ENABLE && AXIS_DRIVER_TYPE_Y2(TMC26X)
extern TMC26XStepper stepperY2;
#define Y2_ENABLE_INIT() NOOP
#define Y2_ENABLE_WRITE(STATE) stepperY2.setEnabled(STATE)
#define Y2_ENABLE_READ() stepperY2.isEnabled()
#endif
// Z2 Stepper
#if HAS_Z2_ENABLE && AXIS_DRIVER_TYPE_Z2(TMC26X)
extern TMC26XStepper stepperZ2;
#define Z2_ENABLE_INIT() NOOP
#define Z2_ENABLE_WRITE(STATE) stepperZ2.setEnabled(STATE)
#define Z2_ENABLE_READ() stepperZ2.isEnabled()
#endif
// Z3 Stepper
#if HAS_Z3_ENABLE && AXIS_DRIVER_TYPE_Z3(TMC26X)
extern TMC26XStepper stepperZ3;
#define Z3_ENABLE_INIT() NOOP
#define Z3_ENABLE_WRITE(STATE) stepperZ3.setEnabled(STATE)
#define Z3_ENABLE_READ() stepperZ3.isEnabled()
#endif
// Z4 Stepper
#if HAS_Z4_ENABLE && AXIS_DRIVER_TYPE_Z4(TMC26X)
extern TMC26XStepper stepperZ4;
#define Z4_ENABLE_INIT() NOOP
#define Z4_ENABLE_WRITE(STATE) stepperZ4.setEnabled(STATE)
#define Z4_ENABLE_READ() stepperZ4.isEnabled()
#endif
// E0 Stepper
#if AXIS_DRIVER_TYPE_E0(TMC26X)
extern TMC26XStepper stepperE0;
#define E0_ENABLE_INIT() NOOP
#define E0_ENABLE_WRITE(STATE) stepperE0.setEnabled(STATE)
#define E0_ENABLE_READ() stepperE0.isEnabled()
#endif
// E1 Stepper
#if AXIS_DRIVER_TYPE_E1(TMC26X)
extern TMC26XStepper stepperE1;
#define E1_ENABLE_INIT() NOOP
#define E1_ENABLE_WRITE(STATE) stepperE1.setEnabled(STATE)
#define E1_ENABLE_READ() stepperE1.isEnabled()
#endif
// E2 Stepper
#if AXIS_DRIVER_TYPE_E2(TMC26X)
extern TMC26XStepper stepperE2;
#define E2_ENABLE_INIT() NOOP
#define E2_ENABLE_WRITE(STATE) stepperE2.setEnabled(STATE)
#define E2_ENABLE_READ() stepperE2.isEnabled()
#endif
// E3 Stepper
#if AXIS_DRIVER_TYPE_E3(TMC26X)
extern TMC26XStepper stepperE3;
#define E3_ENABLE_INIT() NOOP
#define E3_ENABLE_WRITE(STATE) stepperE3.setEnabled(STATE)
#define E3_ENABLE_READ() stepperE3.isEnabled()
#endif
// E4 Stepper
#if AXIS_DRIVER_TYPE_E4(TMC26X)
extern TMC26XStepper stepperE4;
#define E4_ENABLE_INIT() NOOP
#define E4_ENABLE_WRITE(STATE) stepperE4.setEnabled(STATE)
#define E4_ENABLE_READ() stepperE4.isEnabled()
#endif
// E5 Stepper
#if AXIS_DRIVER_TYPE_E5(TMC26X)
extern TMC26XStepper stepperE5;
#define E5_ENABLE_INIT() NOOP
#define E5_ENABLE_WRITE(STATE) stepperE5.setEnabled(STATE)
#define E5_ENABLE_READ() stepperE5.isEnabled()
#endif
// E6 Stepper
#if AXIS_DRIVER_TYPE_E6(TMC26X)
extern TMC26XStepper stepperE6;
#define E6_ENABLE_INIT() NOOP
#define E6_ENABLE_WRITE(STATE) stepperE6.setEnabled(STATE)
#define E6_ENABLE_READ() stepperE6.isEnabled()
#endif
// E7 Stepper
#if AXIS_DRIVER_TYPE_E7(TMC26X)
extern TMC26XStepper stepperE7;
#define E7_ENABLE_INIT() NOOP
#define E7_ENABLE_WRITE(STATE) stepperE7.setEnabled(STATE)
#define E7_ENABLE_READ() stepperE7.isEnabled()
#endif

View File

@@ -0,0 +1,53 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* stepper/indirection.cpp
*
* Stepper motor driver indirection to allow some stepper functions to
* be done via SPI/I2c instead of direct pin manipulation.
*
* Copyright (c) 2015 Dominik Wenger
*/
#include "../../inc/MarlinConfig.h"
#include "indirection.h"
void restore_stepper_drivers() {
#if HAS_TRINAMIC_CONFIG
restore_trinamic_drivers();
#endif
}
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
}

View File

@@ -0,0 +1,985 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* stepper/indirection.h
*
* Stepper motor driver indirection to allow some stepper functions to
* be done via SPI/I2c instead of direct pin manipulation.
*
* Copyright (c) 2015 Dominik Wenger
*/
#include "../../inc/MarlinConfig.h"
#if HAS_L64XX
#include "L64xx.h"
#endif
#if HAS_DRIVER(TMC26X)
#include "TMC26X.h"
#endif
#if HAS_TRINAMIC_CONFIG
#include "trinamic.h"
#endif
void restore_stepper_drivers(); // Called by PSU_ON
void reset_stepper_drivers(); // Called by settings.load / settings.reset
// X Stepper
#ifndef X_ENABLE_INIT
#define X_ENABLE_INIT() SET_OUTPUT(X_ENABLE_PIN)
#define X_ENABLE_WRITE(STATE) WRITE(X_ENABLE_PIN,STATE)
#define X_ENABLE_READ() bool(READ(X_ENABLE_PIN))
#endif
#ifndef X_DIR_INIT
#define X_DIR_INIT() SET_OUTPUT(X_DIR_PIN)
#define X_DIR_WRITE(STATE) WRITE(X_DIR_PIN,STATE)
#define X_DIR_READ() bool(READ(X_DIR_PIN))
#endif
#define X_STEP_INIT() SET_OUTPUT(X_STEP_PIN)
#ifndef X_STEP_WRITE
#define X_STEP_WRITE(STATE) WRITE(X_STEP_PIN,STATE)
#endif
#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))
#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))
#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
#ifndef X2_ENABLE_INIT
#define X2_ENABLE_INIT() SET_OUTPUT(X2_ENABLE_PIN)
#define X2_ENABLE_WRITE(STATE) WRITE(X2_ENABLE_PIN,STATE)
#define X2_ENABLE_READ() bool(READ(X2_ENABLE_PIN))
#endif
#ifndef X2_DIR_INIT
#define X2_DIR_INIT() SET_OUTPUT(X2_DIR_PIN)
#define X2_DIR_WRITE(STATE) WRITE(X2_DIR_PIN,STATE)
#define X2_DIR_READ() bool(READ(X2_DIR_PIN))
#endif
#define X2_STEP_INIT() SET_OUTPUT(X2_STEP_PIN)
#ifndef X2_STEP_WRITE
#define X2_STEP_WRITE(STATE) WRITE(X2_STEP_PIN,STATE)
#endif
#define X2_STEP_READ() bool(READ(X2_STEP_PIN))
#endif
// Y2 Stepper
#if HAS_Y2_ENABLE
#ifndef Y2_ENABLE_INIT
#define Y2_ENABLE_INIT() SET_OUTPUT(Y2_ENABLE_PIN)
#define Y2_ENABLE_WRITE(STATE) WRITE(Y2_ENABLE_PIN,STATE)
#define Y2_ENABLE_READ() bool(READ(Y2_ENABLE_PIN))
#endif
#ifndef Y2_DIR_INIT
#define Y2_DIR_INIT() SET_OUTPUT(Y2_DIR_PIN)
#define Y2_DIR_WRITE(STATE) WRITE(Y2_DIR_PIN,STATE)
#define Y2_DIR_READ() bool(READ(Y2_DIR_PIN))
#endif
#define Y2_STEP_INIT() SET_OUTPUT(Y2_STEP_PIN)
#ifndef Y2_STEP_WRITE
#define Y2_STEP_WRITE(STATE) WRITE(Y2_STEP_PIN,STATE)
#endif
#define Y2_STEP_READ() bool(READ(Y2_STEP_PIN))
#else
#define Y2_DIR_WRITE(STATE) NOOP
#endif
// Z2 Stepper
#if HAS_Z2_ENABLE
#ifndef Z2_ENABLE_INIT
#define Z2_ENABLE_INIT() SET_OUTPUT(Z2_ENABLE_PIN)
#define Z2_ENABLE_WRITE(STATE) WRITE(Z2_ENABLE_PIN,STATE)
#define Z2_ENABLE_READ() bool(READ(Z2_ENABLE_PIN))
#endif
#ifndef Z2_DIR_INIT
#define Z2_DIR_INIT() SET_OUTPUT(Z2_DIR_PIN)
#define Z2_DIR_WRITE(STATE) WRITE(Z2_DIR_PIN,STATE)
#define Z2_DIR_READ() bool(READ(Z2_DIR_PIN))
#endif
#define Z2_STEP_INIT() SET_OUTPUT(Z2_STEP_PIN)
#ifndef Z2_STEP_WRITE
#define Z2_STEP_WRITE(STATE) WRITE(Z2_STEP_PIN,STATE)
#endif
#define Z2_STEP_READ() bool(READ(Z2_STEP_PIN))
#else
#define Z2_DIR_WRITE(STATE) NOOP
#endif
// Z3 Stepper
#if HAS_Z3_ENABLE
#ifndef Z3_ENABLE_INIT
#define Z3_ENABLE_INIT() SET_OUTPUT(Z3_ENABLE_PIN)
#define Z3_ENABLE_WRITE(STATE) WRITE(Z3_ENABLE_PIN,STATE)
#define Z3_ENABLE_READ() bool(READ(Z3_ENABLE_PIN))
#endif
#ifndef Z3_DIR_INIT
#define Z3_DIR_INIT() SET_OUTPUT(Z3_DIR_PIN)
#define Z3_DIR_WRITE(STATE) WRITE(Z3_DIR_PIN,STATE)
#define Z3_DIR_READ() bool(READ(Z3_DIR_PIN))
#endif
#define Z3_STEP_INIT() SET_OUTPUT(Z3_STEP_PIN)
#ifndef Z3_STEP_WRITE
#define Z3_STEP_WRITE(STATE) WRITE(Z3_STEP_PIN,STATE)
#endif
#define Z3_STEP_READ() bool(READ(Z3_STEP_PIN))
#else
#define Z3_DIR_WRITE(STATE) NOOP
#endif
// Z4 Stepper
#if HAS_Z4_ENABLE
#ifndef Z4_ENABLE_INIT
#define Z4_ENABLE_INIT() SET_OUTPUT(Z4_ENABLE_PIN)
#define Z4_ENABLE_WRITE(STATE) WRITE(Z4_ENABLE_PIN,STATE)
#define Z4_ENABLE_READ() bool(READ(Z4_ENABLE_PIN))
#endif
#ifndef Z4_DIR_INIT
#define Z4_DIR_INIT() SET_OUTPUT(Z4_DIR_PIN)
#define Z4_DIR_WRITE(STATE) WRITE(Z4_DIR_PIN,STATE)
#define Z4_DIR_READ() bool(READ(Z4_DIR_PIN))
#endif
#define Z4_STEP_INIT() SET_OUTPUT(Z4_STEP_PIN)
#ifndef Z4_STEP_WRITE
#define Z4_STEP_WRITE(STATE) WRITE(Z4_STEP_PIN,STATE)
#endif
#define Z4_STEP_READ() bool(READ(Z4_STEP_PIN))
#else
#define Z4_DIR_WRITE(STATE) NOOP
#endif
// E0 Stepper
#ifndef E0_ENABLE_INIT
#define E0_ENABLE_INIT() SET_OUTPUT(E0_ENABLE_PIN)
#define E0_ENABLE_WRITE(STATE) WRITE(E0_ENABLE_PIN,STATE)
#define E0_ENABLE_READ() bool(READ(E0_ENABLE_PIN))
#endif
#ifndef E0_DIR_INIT
#define E0_DIR_INIT() SET_OUTPUT(E0_DIR_PIN)
#define E0_DIR_WRITE(STATE) WRITE(E0_DIR_PIN,STATE)
#define E0_DIR_READ() bool(READ(E0_DIR_PIN))
#endif
#define E0_STEP_INIT() SET_OUTPUT(E0_STEP_PIN)
#ifndef E0_STEP_WRITE
#define E0_STEP_WRITE(STATE) WRITE(E0_STEP_PIN,STATE)
#endif
#define E0_STEP_READ() bool(READ(E0_STEP_PIN))
// E1 Stepper
#ifndef E1_ENABLE_INIT
#define E1_ENABLE_INIT() SET_OUTPUT(E1_ENABLE_PIN)
#define E1_ENABLE_WRITE(STATE) WRITE(E1_ENABLE_PIN,STATE)
#define E1_ENABLE_READ() bool(READ(E1_ENABLE_PIN))
#endif
#ifndef E1_DIR_INIT
#define E1_DIR_INIT() SET_OUTPUT(E1_DIR_PIN)
#define E1_DIR_WRITE(STATE) WRITE(E1_DIR_PIN,STATE)
#define E1_DIR_READ() bool(READ(E1_DIR_PIN))
#endif
#define E1_STEP_INIT() SET_OUTPUT(E1_STEP_PIN)
#ifndef E1_STEP_WRITE
#define E1_STEP_WRITE(STATE) WRITE(E1_STEP_PIN,STATE)
#endif
#define E1_STEP_READ() bool(READ(E1_STEP_PIN))
// E2 Stepper
#ifndef E2_ENABLE_INIT
#define E2_ENABLE_INIT() SET_OUTPUT(E2_ENABLE_PIN)
#define E2_ENABLE_WRITE(STATE) WRITE(E2_ENABLE_PIN,STATE)
#define E2_ENABLE_READ() bool(READ(E2_ENABLE_PIN))
#endif
#ifndef E2_DIR_INIT
#define E2_DIR_INIT() SET_OUTPUT(E2_DIR_PIN)
#define E2_DIR_WRITE(STATE) WRITE(E2_DIR_PIN,STATE)
#define E2_DIR_READ() bool(READ(E2_DIR_PIN))
#endif
#define E2_STEP_INIT() SET_OUTPUT(E2_STEP_PIN)
#ifndef E2_STEP_WRITE
#define E2_STEP_WRITE(STATE) WRITE(E2_STEP_PIN,STATE)
#endif
#define E2_STEP_READ() bool(READ(E2_STEP_PIN))
// E3 Stepper
#ifndef E3_ENABLE_INIT
#define E3_ENABLE_INIT() SET_OUTPUT(E3_ENABLE_PIN)
#define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE)
#define E3_ENABLE_READ() bool(READ(E3_ENABLE_PIN))
#endif
#ifndef E3_DIR_INIT
#define E3_DIR_INIT() SET_OUTPUT(E3_DIR_PIN)
#define E3_DIR_WRITE(STATE) WRITE(E3_DIR_PIN,STATE)
#define E3_DIR_READ() bool(READ(E3_DIR_PIN))
#endif
#define E3_STEP_INIT() SET_OUTPUT(E3_STEP_PIN)
#ifndef E3_STEP_WRITE
#define E3_STEP_WRITE(STATE) WRITE(E3_STEP_PIN,STATE)
#endif
#define E3_STEP_READ() bool(READ(E3_STEP_PIN))
// E4 Stepper
#ifndef E4_ENABLE_INIT
#define E4_ENABLE_INIT() SET_OUTPUT(E4_ENABLE_PIN)
#define E4_ENABLE_WRITE(STATE) WRITE(E4_ENABLE_PIN,STATE)
#define E4_ENABLE_READ() bool(READ(E4_ENABLE_PIN))
#endif
#ifndef E4_DIR_INIT
#define E4_DIR_INIT() SET_OUTPUT(E4_DIR_PIN)
#define E4_DIR_WRITE(STATE) WRITE(E4_DIR_PIN,STATE)
#define E4_DIR_READ() bool(READ(E4_DIR_PIN))
#endif
#define E4_STEP_INIT() SET_OUTPUT(E4_STEP_PIN)
#ifndef E4_STEP_WRITE
#define E4_STEP_WRITE(STATE) WRITE(E4_STEP_PIN,STATE)
#endif
#define E4_STEP_READ() bool(READ(E4_STEP_PIN))
// E5 Stepper
#ifndef E5_ENABLE_INIT
#define E5_ENABLE_INIT() SET_OUTPUT(E5_ENABLE_PIN)
#define E5_ENABLE_WRITE(STATE) WRITE(E5_ENABLE_PIN,STATE)
#define E5_ENABLE_READ() bool(READ(E5_ENABLE_PIN))
#endif
#ifndef E5_DIR_INIT
#define E5_DIR_INIT() SET_OUTPUT(E5_DIR_PIN)
#define E5_DIR_WRITE(STATE) WRITE(E5_DIR_PIN,STATE)
#define E5_DIR_READ() bool(READ(E5_DIR_PIN))
#endif
#define E5_STEP_INIT() SET_OUTPUT(E5_STEP_PIN)
#ifndef E5_STEP_WRITE
#define E5_STEP_WRITE(STATE) WRITE(E5_STEP_PIN,STATE)
#endif
#define E5_STEP_READ() bool(READ(E5_STEP_PIN))
// E6 Stepper
#ifndef E6_ENABLE_INIT
#define E6_ENABLE_INIT() SET_OUTPUT(E6_ENABLE_PIN)
#define E6_ENABLE_WRITE(STATE) WRITE(E6_ENABLE_PIN,STATE)
#define E6_ENABLE_READ() bool(READ(E6_ENABLE_PIN))
#endif
#ifndef E6_DIR_INIT
#define E6_DIR_INIT() SET_OUTPUT(E6_DIR_PIN)
#define E6_DIR_WRITE(STATE) WRITE(E6_DIR_PIN,STATE)
#define E6_DIR_READ() bool(READ(E6_DIR_PIN))
#endif
#define E6_STEP_INIT() SET_OUTPUT(E6_STEP_PIN)
#ifndef E6_STEP_WRITE
#define E6_STEP_WRITE(STATE) WRITE(E6_STEP_PIN,STATE)
#endif
#define E6_STEP_READ() bool(READ(E6_STEP_PIN))
// E7 Stepper
#ifndef E7_ENABLE_INIT
#define E7_ENABLE_INIT() SET_OUTPUT(E7_ENABLE_PIN)
#define E7_ENABLE_WRITE(STATE) WRITE(E7_ENABLE_PIN,STATE)
#define E7_ENABLE_READ() bool(READ(E7_ENABLE_PIN))
#endif
#ifndef E7_DIR_INIT
#define E7_DIR_INIT() SET_OUTPUT(E7_DIR_PIN)
#define E7_DIR_WRITE(STATE) WRITE(E7_DIR_PIN,STATE)
#define E7_DIR_READ() bool(READ(E7_DIR_PIN))
#endif
#define E7_STEP_INIT() SET_OUTPUT(E7_STEP_PIN)
#ifndef E7_STEP_WRITE
#define E7_STEP_WRITE(STATE) WRITE(E7_STEP_PIN,STATE)
#endif
#define E7_STEP_READ() bool(READ(E7_STEP_PIN))
/**
* Extruder indirection for the single E axis
*/
#if ENABLED(SWITCHING_EXTRUDER) // One stepper driver per two extruders, reversed on odd index
#if EXTRUDERS > 7
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else if (E < 4) { E1_STEP_WRITE(V); } else if (E < 6) { E2_STEP_WRITE(V); } else { E3_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 3: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 5: E2_DIR_WRITE( INVERT_E2_DIR); break; \
case 6: E3_DIR_WRITE( INVERT_E3_DIR); break; case 7: E3_DIR_WRITE( INVERT_E3_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; case 3: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE( INVERT_E2_DIR); break; case 5: E2_DIR_WRITE(!INVERT_E2_DIR); break; \
case 6: E3_DIR_WRITE(!INVERT_E3_DIR); break; case 7: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
} }while(0)
#elif EXTRUDERS > 6
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else if (E < 4) { E1_STEP_WRITE(V); } else if (E < 6) { E2_STEP_WRITE(V); } else { E3_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 3: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 5: E2_DIR_WRITE( INVERT_E2_DIR); break; \
case 6: E3_DIR_WRITE( INVERT_E3_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; case 3: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE( INVERT_E2_DIR); break; case 5: E2_DIR_WRITE(!INVERT_E2_DIR); break; \
case 6: E3_DIR_WRITE(!INVERT_E3_DIR); } }while(0)
#elif EXTRUDERS > 5
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else if (E < 4) { E1_STEP_WRITE(V); } else { E2_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 3: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 5: E2_DIR_WRITE( INVERT_E2_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; case 3: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE( INVERT_E2_DIR); break; case 5: E2_DIR_WRITE(!INVERT_E2_DIR); break; \
} }while(0)
#elif EXTRUDERS > 4
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else if (E < 4) { E1_STEP_WRITE(V); } else { E2_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 3: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE(!INVERT_E2_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; case 3: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 4: E2_DIR_WRITE( INVERT_E2_DIR); break; \
} }while(0)
#elif EXTRUDERS > 3
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 3: E1_DIR_WRITE( INVERT_E1_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; case 3: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
} }while(0)
#elif EXTRUDERS > 2
#define E_STEP_WRITE(E,V) do{ if (E < 2) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
#define NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E0_DIR_WRITE( INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
} }while(0)
#define REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E0_DIR_WRITE(!INVERT_E0_DIR); break; \
case 2: E1_DIR_WRITE( INVERT_E1_DIR); break; \
} }while(0)
#else
#define E_STEP_WRITE(E,V) E0_STEP_WRITE(V)
#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)
#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
#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)
#elif E_STEPPERS > 1
#if E_STEPPERS > 7
#define _E_STEP_WRITE(E,V) do{ switch (E) { \
case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); break; case 3: E3_STEP_WRITE(V); break; \
case 4: E4_STEP_WRITE(V); break; case 5: E5_STEP_WRITE(V); break; case 6: E6_STEP_WRITE(V); break; case 7: E7_STEP_WRITE(V); break; \
} }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE(!INVERT_E4_DIR); break; case 5: E5_DIR_WRITE(!INVERT_E5_DIR); break; \
case 6: E6_DIR_WRITE(!INVERT_E6_DIR); break; case 7: E7_DIR_WRITE(!INVERT_E7_DIR); break; \
} }while(0)
#define _REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE( INVERT_E2_DIR); break; case 3: E3_DIR_WRITE( INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE( INVERT_E4_DIR); break; case 5: E5_DIR_WRITE( INVERT_E5_DIR); break; \
case 6: E6_DIR_WRITE( INVERT_E6_DIR); break; case 7: E7_DIR_WRITE( INVERT_E7_DIR); break; \
} }while(0)
#elif E_STEPPERS > 6
#define _E_STEP_WRITE(E,V) do{ switch (E) { \
case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); break; case 3: E3_STEP_WRITE(V); break; \
case 4: E4_STEP_WRITE(V); break; case 5: E5_STEP_WRITE(V); break; case 6: E6_STEP_WRITE(V); break; \
} }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE(!INVERT_E4_DIR); break; case 5: E5_DIR_WRITE(!INVERT_E5_DIR); break; \
case 6: E6_DIR_WRITE(!INVERT_E6_DIR); break; \
} }while(0)
#define _REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE( INVERT_E2_DIR); break; case 3: E3_DIR_WRITE( INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE( INVERT_E4_DIR); break; case 5: E5_DIR_WRITE( INVERT_E5_DIR); break; \
case 6: E6_DIR_WRITE( INVERT_E6_DIR); break; \
} }while(0)
#elif E_STEPPERS > 5
#define _E_STEP_WRITE(E,V) do{ switch (E) { \
case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); break; case 3: E3_STEP_WRITE(V); break; \
case 4: E4_STEP_WRITE(V); break; case 5: E5_STEP_WRITE(V); break; \
} }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE(!INVERT_E4_DIR); break; case 5: E5_DIR_WRITE(!INVERT_E5_DIR); break; \
} }while(0)
#define _REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE( INVERT_E2_DIR); break; case 3: E3_DIR_WRITE( INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE( INVERT_E4_DIR); break; case 5: E5_DIR_WRITE( INVERT_E5_DIR); break; \
} }while(0)
#elif E_STEPPERS > 4
#define _E_STEP_WRITE(E,V) do{ switch (E) { \
case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); break; case 3: E3_STEP_WRITE(V); break; \
case 4: E4_STEP_WRITE(V); break; \
} }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE(!INVERT_E4_DIR); break; \
} }while(0)
#define _REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE( INVERT_E2_DIR); break; case 3: E3_DIR_WRITE( INVERT_E3_DIR); break; \
case 4: E4_DIR_WRITE( INVERT_E4_DIR); break; \
} }while(0)
#elif E_STEPPERS > 3
#define _E_STEP_WRITE(E,V) do{ switch (E) { \
case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); break; case 3: E3_STEP_WRITE(V); break; \
} }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE(!INVERT_E2_DIR); break; case 3: E3_DIR_WRITE(!INVERT_E3_DIR); break; \
} }while(0)
#define _REV_E_DIR(E) do{ switch (E) { \
case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; \
case 2: E2_DIR_WRITE( INVERT_E2_DIR); break; case 3: E3_DIR_WRITE( INVERT_E3_DIR); break; \
} }while(0)
#elif E_STEPPERS > 2
#define _E_STEP_WRITE(E,V) do{ switch (E) { case 0: E0_STEP_WRITE(V); break; case 1: E1_STEP_WRITE(V); break; case 2: E2_STEP_WRITE(V); } }while(0)
#define _NORM_E_DIR(E) do{ switch (E) { case 0: E0_DIR_WRITE(!INVERT_E0_DIR); break; case 1: E1_DIR_WRITE(!INVERT_E1_DIR); break; case 2: E2_DIR_WRITE(!INVERT_E2_DIR); } }while(0)
#define _REV_E_DIR(E) do{ switch (E) { case 0: E0_DIR_WRITE( INVERT_E0_DIR); break; case 1: E1_DIR_WRITE( INVERT_E1_DIR); break; case 2: E2_DIR_WRITE( INVERT_E2_DIR); } }while(0)
#else
#define _E_STEP_WRITE(E,V) do{ if (E == 0) { E0_STEP_WRITE(V); } else { E1_STEP_WRITE(V); } }while(0)
#define _NORM_E_DIR(E) do{ if (E == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }while(0)
#define _REV_E_DIR(E) do{ if (E == 0) { E0_DIR_WRITE( INVERT_E0_DIR); } else { E1_DIR_WRITE( INVERT_E1_DIR); } }while(0)
#endif
#if HAS_DUPLICATION_MODE
#if ENABLED(MULTI_NOZZLE_DUPLICATION)
#define _DUPE(N,T,V) do{ if (TEST(duplication_e_mask, N)) E##N##_##T##_WRITE(V); }while(0)
#else
#define _DUPE(N,T,V) E##N##_##T##_WRITE(V)
#endif
#define NDIR(N) _DUPE(N,DIR,!INVERT_E##N##_DIR)
#define RDIR(N) _DUPE(N,DIR, INVERT_E##N##_DIR)
#define E_STEP_WRITE(E,V) do{ if (extruder_duplication_enabled) { DUPE(STEP,V); } else _E_STEP_WRITE(E,V); }while(0)
#if E_STEPPERS > 2
#if E_STEPPERS > 7
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); _DUPE(3,T,V); _DUPE(4,T,V); _DUPE(5,T,V); _DUPE(6,T,V); _DUPE(7,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); NDIR(3); NDIR(4); NDIR(5); NDIR(6); NDIR(7); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); RDIR(3); RDIR(4); RDIR(5); RDIR(6); RDIR(7); } else _REV_E_DIR(E); }while(0)
#elif E_STEPPERS > 6
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); _DUPE(3,T,V); _DUPE(4,T,V); _DUPE(5,T,V); _DUPE(6,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); NDIR(3); NDIR(4); NDIR(5); NDIR(6); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); RDIR(3); RDIR(4); RDIR(5); RDIR(6); } else _REV_E_DIR(E); }while(0)
#elif E_STEPPERS > 5
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); _DUPE(3,T,V); _DUPE(4,T,V); _DUPE(5,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); NDIR(3); NDIR(4); NDIR(5); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); RDIR(3); RDIR(4); RDIR(5); } else _REV_E_DIR(E); }while(0)
#elif E_STEPPERS > 4
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); _DUPE(3,T,V); _DUPE(4,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); NDIR(3); NDIR(4); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); RDIR(3); RDIR(4); } else _REV_E_DIR(E); }while(0)
#elif E_STEPPERS > 3
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); _DUPE(3,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); NDIR(3); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); RDIR(3); } else _REV_E_DIR(E); }while(0)
#else
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); _DUPE(2,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); NDIR(2); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); RDIR(2); } else _REV_E_DIR(E); }while(0)
#endif
#else
#define DUPE(T,V) do{ _DUPE(0,T,V); _DUPE(1,T,V); }while(0)
#define NORM_E_DIR(E) do{ if (extruder_duplication_enabled) { NDIR(0); NDIR(1); } else _NORM_E_DIR(E); }while(0)
#define REV_E_DIR(E) do{ if (extruder_duplication_enabled) { RDIR(0); RDIR(1); } else _REV_E_DIR(E); }while(0)
#endif
#else
#define E_STEP_WRITE(E,V) _E_STEP_WRITE(E,V)
#define NORM_E_DIR(E) _NORM_E_DIR(E)
#define REV_E_DIR(E) _REV_E_DIR(E)
#endif
#elif E_STEPPERS
#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)
#else
#define E_STEP_WRITE(E,V) NOOP
#define NORM_E_DIR(E) NOOP
#define REV_E_DIR(E) NOOP
#endif
//
// Individual stepper enable / disable macros
//
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#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
#endif
#ifndef ENABLE_STEPPER_E1
#if E_STEPPERS > 1 && HAS_E1_ENABLE
#define ENABLE_STEPPER_E1() E1_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E1() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E1
#if E_STEPPERS > 1 && HAS_E1_ENABLE
#define DISABLE_STEPPER_E1() E1_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E1() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E2
#if E_STEPPERS > 2 && HAS_E2_ENABLE
#define ENABLE_STEPPER_E2() E2_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E2() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E2
#if E_STEPPERS > 2 && HAS_E2_ENABLE
#define DISABLE_STEPPER_E2() E2_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E2() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E3
#if E_STEPPERS > 3 && HAS_E3_ENABLE
#define ENABLE_STEPPER_E3() E3_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E3() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E3
#if E_STEPPERS > 3 && HAS_E3_ENABLE
#define DISABLE_STEPPER_E3() E3_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E3() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E4
#if E_STEPPERS > 4 && HAS_E4_ENABLE
#define ENABLE_STEPPER_E4() E4_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E4() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E4
#if E_STEPPERS > 4 && HAS_E4_ENABLE
#define DISABLE_STEPPER_E4() E4_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E4() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E5
#if E_STEPPERS > 5 && HAS_E5_ENABLE
#define ENABLE_STEPPER_E5() E5_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E5() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E5
#if E_STEPPERS > 5 && HAS_E5_ENABLE
#define DISABLE_STEPPER_E5() E5_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E5() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E6
#if E_STEPPERS > 6 && HAS_E6_ENABLE
#define ENABLE_STEPPER_E6() E6_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E6() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E6
#if E_STEPPERS > 6 && HAS_E6_ENABLE
#define DISABLE_STEPPER_E6() E6_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E6() NOOP
#endif
#endif
#ifndef ENABLE_STEPPER_E7
#if E_STEPPERS > 7 && HAS_E7_ENABLE
#define ENABLE_STEPPER_E7() E7_ENABLE_WRITE( E_ENABLE_ON)
#else
#define ENABLE_STEPPER_E7() NOOP
#endif
#endif
#ifndef DISABLE_STEPPER_E7
#if E_STEPPERS > 7 && HAS_E7_ENABLE
#define DISABLE_STEPPER_E7() E7_ENABLE_WRITE(!E_ENABLE_ON)
#else
#define DISABLE_STEPPER_E7() NOOP
#endif
#endif
//
// Axis steppers enable / disable macros
//
#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_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)
#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)
//
// Extruder steppers enable / disable macros
//
#if ENABLED(MIXING_EXTRUDER)
/**
* Mixing steppers keep all their enable (and direction) states synchronized
*/
#define _CALL_ENA_E(N) ENABLE_STEPPER_E##N () ;
#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) }
#endif
#ifndef ENABLE_AXIS_E0
#if E_STEPPERS > 0 && 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
#define DISABLE_AXIS_E0() DISABLE_STEPPER_E0()
#else
#define DISABLE_AXIS_E0() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E1
#if E_STEPPERS > 1 && HAS_E1_ENABLE
#define ENABLE_AXIS_E1() ENABLE_STEPPER_E1()
#else
#define ENABLE_AXIS_E1() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E1
#if E_STEPPERS > 1 && HAS_E1_ENABLE
#define DISABLE_AXIS_E1() DISABLE_STEPPER_E1()
#else
#define DISABLE_AXIS_E1() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E2
#if E_STEPPERS > 2 && HAS_E2_ENABLE
#define ENABLE_AXIS_E2() ENABLE_STEPPER_E2()
#else
#define ENABLE_AXIS_E2() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E2
#if E_STEPPERS > 2 && HAS_E2_ENABLE
#define DISABLE_AXIS_E2() DISABLE_STEPPER_E2()
#else
#define DISABLE_AXIS_E2() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E3
#if E_STEPPERS > 3 && HAS_E3_ENABLE
#define ENABLE_AXIS_E3() ENABLE_STEPPER_E3()
#else
#define ENABLE_AXIS_E3() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E3
#if E_STEPPERS > 3 && HAS_E3_ENABLE
#define DISABLE_AXIS_E3() DISABLE_STEPPER_E3()
#else
#define DISABLE_AXIS_E3() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E4
#if E_STEPPERS > 4 && HAS_E4_ENABLE
#define ENABLE_AXIS_E4() ENABLE_STEPPER_E4()
#else
#define ENABLE_AXIS_E4() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E4
#if E_STEPPERS > 4 && HAS_E4_ENABLE
#define DISABLE_AXIS_E4() DISABLE_STEPPER_E4()
#else
#define DISABLE_AXIS_E4() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E5
#if E_STEPPERS > 5 && HAS_E5_ENABLE
#define ENABLE_AXIS_E5() ENABLE_STEPPER_E5()
#else
#define ENABLE_AXIS_E5() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E5
#if E_STEPPERS > 5 && HAS_E5_ENABLE
#define DISABLE_AXIS_E5() DISABLE_STEPPER_E5()
#else
#define DISABLE_AXIS_E5() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E6
#if E_STEPPERS > 6 && HAS_E6_ENABLE
#define ENABLE_AXIS_E6() ENABLE_STEPPER_E6()
#else
#define ENABLE_AXIS_E6() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E6
#if E_STEPPERS > 6 && HAS_E6_ENABLE
#define DISABLE_AXIS_E6() DISABLE_STEPPER_E6()
#else
#define DISABLE_AXIS_E6() NOOP
#endif
#endif
#ifndef ENABLE_AXIS_E7
#if E_STEPPERS > 7 && HAS_E7_ENABLE
#define ENABLE_AXIS_E7() ENABLE_STEPPER_E7()
#else
#define ENABLE_AXIS_E7() NOOP
#endif
#endif
#ifndef DISABLE_AXIS_E7
#if E_STEPPERS > 7 && HAS_E7_ENABLE
#define DISABLE_AXIS_E7() DISABLE_STEPPER_E7()
#else
#define DISABLE_AXIS_E7() NOOP
#endif
#endif

View File

@@ -0,0 +1,821 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
/**
* stepper/trinamic.cpp
* Stepper driver indirection for Trinamic
*/
#include "../../inc/MarlinConfig.h"
#if HAS_TRINAMIC_CONFIG
#include "trinamic.h"
#include "../stepper.h"
#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])
// IC = TMC model number
// ST = Stepper object letter
// L = Label characters
// AI = Axis Enum Index
// SWHW = SW/SH UART selection
#if ENABLED(TMC_USE_SW_SPI)
#define __TMC_SPI_DEFINE(IC, ST, L, AI) TMCMarlin<IC##Stepper, L, AI> stepper##ST(ST##_CS_PIN, float(ST##_RSENSE), TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK, ST##_CHAIN_POS)
#else
#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)
#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)
#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
#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
#define TMC_SPI_DEFINE_E(AI) TMC_SPI_DEFINE(E##AI, E)
#define TMC_UART_DEFINE_E(SWHW, AI) TMC_UART_DEFINE(SWHW, E##AI, E)
#endif
// Stepper objects of TMC2130/TMC2160/TMC2660/TMC5130/TMC5160 steppers used
#if AXIS_HAS_SPI(X)
TMC_SPI_DEFINE(X, X);
#endif
#if AXIS_HAS_SPI(X2)
TMC_SPI_DEFINE(X2, X);
#endif
#if AXIS_HAS_SPI(Y)
TMC_SPI_DEFINE(Y, Y);
#endif
#if AXIS_HAS_SPI(Y2)
TMC_SPI_DEFINE(Y2, Y);
#endif
#if AXIS_HAS_SPI(Z)
TMC_SPI_DEFINE(Z, Z);
#endif
#if AXIS_HAS_SPI(Z2)
TMC_SPI_DEFINE(Z2, Z);
#endif
#if AXIS_HAS_SPI(Z3)
TMC_SPI_DEFINE(Z3, Z);
#endif
#if AXIS_HAS_SPI(Z4)
TMC_SPI_DEFINE(Z4, Z);
#endif
#if AXIS_HAS_SPI(E0)
TMC_SPI_DEFINE_E(0);
#endif
#if AXIS_HAS_SPI(E1)
TMC_SPI_DEFINE_E(1);
#endif
#if AXIS_HAS_SPI(E2)
TMC_SPI_DEFINE_E(2);
#endif
#if AXIS_HAS_SPI(E3)
TMC_SPI_DEFINE_E(3);
#endif
#if AXIS_HAS_SPI(E4)
TMC_SPI_DEFINE_E(4);
#endif
#if AXIS_HAS_SPI(E5)
TMC_SPI_DEFINE_E(5);
#endif
#if AXIS_HAS_SPI(E6)
TMC_SPI_DEFINE_E(6);
#endif
#if AXIS_HAS_SPI(E7)
TMC_SPI_DEFINE_E(7);
#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
#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) {
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;
PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(); // Clear GSTAT
}
#endif // TMC2130
#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) {
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;
TMC2160_n::PWMCONF_t pwmconf{0};
pwmconf.pwm_lim = 12;
pwmconf.pwm_reg = 8;
pwmconf.pwm_autograd = true;
pwmconf.pwm_autoscale = true;
pwmconf.pwm_freq = 0b01;
pwmconf.pwm_grad = 14;
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(); // Clear GSTAT
}
#endif // TMC2160
//
// TMC2208/2209 Driver objects and inits
//
#if HAS_TMC220x
#if AXIS_HAS_UART(X)
#ifdef X_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, X, X);
#else
TMC_UART_DEFINE(SW, X, X);
#endif
#endif
#if AXIS_HAS_UART(X2)
#ifdef X2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, X2, X);
#else
TMC_UART_DEFINE(SW, X2, X);
#endif
#endif
#if AXIS_HAS_UART(Y)
#ifdef Y_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Y, Y);
#else
TMC_UART_DEFINE(SW, Y, Y);
#endif
#endif
#if AXIS_HAS_UART(Y2)
#ifdef Y2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Y2, Y);
#else
TMC_UART_DEFINE(SW, Y2, Y);
#endif
#endif
#if AXIS_HAS_UART(Z)
#ifdef Z_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z, Z);
#else
TMC_UART_DEFINE(SW, Z, Z);
#endif
#endif
#if AXIS_HAS_UART(Z2)
#ifdef Z2_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z2, Z);
#else
TMC_UART_DEFINE(SW, Z2, Z);
#endif
#endif
#if AXIS_HAS_UART(Z3)
#ifdef Z3_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z3, Z);
#else
TMC_UART_DEFINE(SW, Z3, Z);
#endif
#endif
#if AXIS_HAS_UART(Z4)
#ifdef Z4_HARDWARE_SERIAL
TMC_UART_DEFINE(HW, Z4, Z);
#else
TMC_UART_DEFINE(SW, Z4, Z);
#endif
#endif
#if AXIS_HAS_UART(E0)
#ifdef E0_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 0);
#else
TMC_UART_DEFINE_E(SW, 0);
#endif
#endif
#if AXIS_HAS_UART(E1)
#ifdef E1_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 1);
#else
TMC_UART_DEFINE_E(SW, 1);
#endif
#endif
#if AXIS_HAS_UART(E2)
#ifdef E2_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 2);
#else
TMC_UART_DEFINE_E(SW, 2);
#endif
#endif
#if AXIS_HAS_UART(E3)
#ifdef E3_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 3);
#else
TMC_UART_DEFINE_E(SW, 3);
#endif
#endif
#if AXIS_HAS_UART(E4)
#ifdef E4_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 4);
#else
TMC_UART_DEFINE_E(SW, 4);
#endif
#endif
#if AXIS_HAS_UART(E5)
#ifdef E5_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 5);
#else
TMC_UART_DEFINE_E(SW, 5);
#endif
#endif
#if AXIS_HAS_UART(E6)
#ifdef E6_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 6);
#else
TMC_UART_DEFINE_E(SW, 6);
#endif
#endif
#if AXIS_HAS_UART(E7)
#ifdef E7_HARDWARE_SERIAL
TMC_UART_DEFINE_E(HW, 7);
#else
TMC_UART_DEFINE_E(SW, 7);
#endif
#endif
void tmc_serial_begin() {
#if AXIS_HAS_UART(X)
#ifdef X_HARDWARE_SERIAL
X_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperX.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(X2)
#ifdef X2_HARDWARE_SERIAL
X2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperX2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Y)
#ifdef Y_HARDWARE_SERIAL
Y_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperY.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Y2)
#ifdef Y2_HARDWARE_SERIAL
Y2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperY2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z)
#ifdef Z_HARDWARE_SERIAL
Z_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperZ.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z2)
#ifdef Z2_HARDWARE_SERIAL
Z2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperZ2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z3)
#ifdef Z3_HARDWARE_SERIAL
Z3_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperZ3.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(Z4)
#ifdef Z4_HARDWARE_SERIAL
Z4_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperZ4.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E0)
#ifdef E0_HARDWARE_SERIAL
E0_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE0.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E1)
#ifdef E1_HARDWARE_SERIAL
E1_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE1.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E2)
#ifdef E2_HARDWARE_SERIAL
E2_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE2.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E3)
#ifdef E3_HARDWARE_SERIAL
E3_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE3.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E4)
#ifdef E4_HARDWARE_SERIAL
E4_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE4.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E5)
#ifdef E5_HARDWARE_SERIAL
E5_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE5.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E6)
#ifdef E6_HARDWARE_SERIAL
E6_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE6.beginSerial(TMC_BAUD_RATE);
#endif
#endif
#if AXIS_HAS_UART(E7)
#ifdef E7_HARDWARE_SERIAL
E7_HARDWARE_SERIAL.begin(TMC_BAUD_RATE);
#else
stepperE7.beginSerial(TMC_BAUD_RATE);
#endif
#endif
}
#endif
#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) {
TMC2208_n::GCONF_t gconf{0};
gconf.pdn_disable = true; // Use UART
gconf.mstep_reg_select = true; // Select microsteps with UART
gconf.i_scale_analog = false;
gconf.en_spreadcycle = !stealth;
st.GCONF(gconf.sr);
st.stored.stealthChop_enabled = stealth;
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
TMC2208_n::PWMCONF_t pwmconf{0};
pwmconf.pwm_lim = 12;
pwmconf.pwm_reg = 8;
pwmconf.pwm_autograd = true;
pwmconf.pwm_autoscale = true;
pwmconf.pwm_freq = 0b01;
pwmconf.pwm_grad = 14;
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(0b111); // Clear
delay(200);
}
#endif // TMC2208
#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) {
TMC2208_n::GCONF_t gconf{0};
gconf.pdn_disable = true; // Use UART
gconf.mstep_reg_select = true; // Select microsteps with UART
gconf.i_scale_analog = false;
gconf.en_spreadcycle = !stealth;
st.GCONF(gconf.sr);
st.stored.stealthChop_enabled = stealth;
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
TMC2208_n::PWMCONF_t pwmconf{0};
pwmconf.pwm_lim = 12;
pwmconf.pwm_reg = 8;
pwmconf.pwm_autograd = true;
pwmconf.pwm_autoscale = true;
pwmconf.pwm_freq = 0b01;
pwmconf.pwm_grad = 14;
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(0b111); // Clear
delay(200);
}
#endif // TMC2209
#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) {
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;
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);
st.diss2g(true); // Disable short to ground protection. Too many false readings?
#if ENABLED(TMC_DEBUG)
st.rdsel(0b01);
#endif
}
#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) {
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;
PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(); // Clear GSTAT
}
#endif // TMC5130
#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) {
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
st.CHOPCONF(chopconf.sr);
st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;
TMC2160_n::PWMCONF_t pwmconf{0};
pwmconf.pwm_lim = 12;
pwmconf.pwm_reg = 8;
pwmconf.pwm_autograd = true;
pwmconf.pwm_autoscale = true;
pwmconf.pwm_freq = 0b01;
pwmconf.pwm_grad = 14;
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);
#if ENABLED(HYBRID_THRESHOLD)
st.set_pwm_thrs(hyb_thrs);
#else
UNUSED(hyb_thrs);
#endif
st.GSTAT(); // Clear GSTAT
}
#endif // TMC5160
void restore_trinamic_drivers() {
#if AXIS_IS_TMC(X)
stepperX.push();
#endif
#if AXIS_IS_TMC(X2)
stepperX2.push();
#endif
#if AXIS_IS_TMC(Y)
stepperY.push();
#endif
#if AXIS_IS_TMC(Y2)
stepperY2.push();
#endif
#if AXIS_IS_TMC(Z)
stepperZ.push();
#endif
#if AXIS_IS_TMC(Z2)
stepperZ2.push();
#endif
#if AXIS_IS_TMC(Z3)
stepperZ3.push();
#endif
#if AXIS_IS_TMC(Z4)
stepperZ4.push();
#endif
#if AXIS_IS_TMC(E0)
stepperE0.push();
#endif
#if AXIS_IS_TMC(E1)
stepperE1.push();
#endif
#if AXIS_IS_TMC(E2)
stepperE2.push();
#endif
#if AXIS_IS_TMC(E3)
stepperE3.push();
#endif
#if AXIS_IS_TMC(E4)
stepperE4.push();
#endif
#if AXIS_IS_TMC(E5)
stepperE5.push();
#endif
#if AXIS_IS_TMC(E6)
stepperE6.push();
#endif
#if AXIS_IS_TMC(E7)
stepperE7.push();
#endif
}
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
};
#if AXIS_IS_TMC(X)
TMC_INIT(X, STEALTH_AXIS_XY);
#endif
#if AXIS_IS_TMC(X2)
TMC_INIT(X2, STEALTH_AXIS_XY);
#endif
#if AXIS_IS_TMC(Y)
TMC_INIT(Y, STEALTH_AXIS_XY);
#endif
#if AXIS_IS_TMC(Y2)
TMC_INIT(Y2, STEALTH_AXIS_XY);
#endif
#if AXIS_IS_TMC(Z)
TMC_INIT(Z, STEALTH_AXIS_Z);
#endif
#if AXIS_IS_TMC(Z2)
TMC_INIT(Z2, STEALTH_AXIS_Z);
#endif
#if AXIS_IS_TMC(Z3)
TMC_INIT(Z3, STEALTH_AXIS_Z);
#endif
#if AXIS_IS_TMC(Z4)
TMC_INIT(Z4, STEALTH_AXIS_Z);
#endif
#if AXIS_IS_TMC(E0)
TMC_INIT(E0, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E1)
TMC_INIT(E1, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E2)
TMC_INIT(E2, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E3)
TMC_INIT(E3, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E4)
TMC_INIT(E4, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E5)
TMC_INIT(E5, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E6)
TMC_INIT(E6, STEALTH_AXIS_E);
#endif
#if AXIS_IS_TMC(E7)
TMC_INIT(E7, STEALTH_AXIS_E);
#endif
#if USE_SENSORLESS
#if X_SENSORLESS
#if AXIS_HAS_STALLGUARD(X)
stepperX.homing_threshold(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
#if AXIS_HAS_STALLGUARD(Y2)
stepperY2.homing_threshold(Y_STALL_SENSITIVITY);
#endif
#endif
#if Z_SENSORLESS
#if AXIS_HAS_STALLGUARD(Z)
stepperZ.homing_threshold(Z_STALL_SENSITIVITY);
#endif
#if AXIS_HAS_STALLGUARD(Z2)
stepperZ2.homing_threshold(Z_STALL_SENSITIVITY);
#endif
#if AXIS_HAS_STALLGUARD(Z3)
stepperZ3.homing_threshold(Z_STALL_SENSITIVITY);
#endif
#if AXIS_HAS_STALLGUARD(Z4)
stepperZ4.homing_threshold(Z_STALL_SENSITIVITY);
#endif
#endif
#endif
#ifdef TMC_ADV
TMC_ADV()
#endif
stepper.set_directions();
}
#endif // HAS_TRINAMIC_CONFIG

View File

@@ -0,0 +1,296 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* stepper/trinamic.h
* Stepper driver indirection for Trinamic
*/
#include <TMCStepper.h>
#if TMCSTEPPER_VERSION < 0x000500
#error "Update TMCStepper library to 0.5.0 or newer."
#endif
#include "../../inc/MarlinConfig.h"
#include "../../feature/tmc_util.h"
#define CLASS_TMC2130 TMC2130Stepper
#define CLASS_TMC2160 TMC2160Stepper
#define CLASS_TMC2208 TMC2208Stepper
#define CLASS_TMC2209 TMC2209Stepper
#define CLASS_TMC2660 TMC2660Stepper
#define CLASS_TMC5130 TMC5130Stepper
#define CLASS_TMC5160 TMC5160Stepper
#define TMC_X_LABEL 'X', '0'
#define TMC_Y_LABEL 'Y', '0'
#define TMC_Z_LABEL 'Z', '0'
#define TMC_X2_LABEL 'X', '2'
#define TMC_Y2_LABEL 'Y', '2'
#define TMC_Z2_LABEL 'Z', '2'
#define TMC_Z3_LABEL 'Z', '3'
#define TMC_Z4_LABEL 'Z', '4'
#define TMC_E0_LABEL 'E', '0'
#define TMC_E1_LABEL 'E', '1'
#define TMC_E2_LABEL 'E', '2'
#define TMC_E3_LABEL 'E', '3'
#define TMC_E4_LABEL 'E', '4'
#define TMC_E5_LABEL 'E', '5'
#define TMC_E6_LABEL 'E', '6'
#define TMC_E7_LABEL 'E', '7'
#define __TMC_CLASS(TYPE, L, I, A) TMCMarlin<CLASS_##TYPE, L, I, A>
#define _TMC_CLASS(TYPE, LandI, A) __TMC_CLASS(TYPE, LandI, A)
#define TMC_CLASS(ST, A) _TMC_CLASS(ST##_DRIVER_TYPE, TMC_##ST##_LABEL, A##_AXIS)
#if ENABLED(DISTINCT_E_FACTORS)
#define TMC_CLASS_E(N) TMC_CLASS(E##N, E##N)
#else
#define TMC_CLASS_E(N) TMC_CLASS(E##N, E)
#endif
typedef struct {
uint8_t toff;
int8_t hend;
uint8_t hstrt;
} chopper_timing_t;
static constexpr chopper_timing_t chopper_timing = CHOPPER_TIMING;
#if HAS_TMC220x
void tmc_serial_begin();
#endif
void restore_trinamic_drivers();
void reset_trinamic_drivers();
#define AXIS_HAS_SQUARE_WAVE(A) (AXIS_IS_TMC(A) && ENABLED(SQUARE_WAVE_STEPPING))
// X Stepper
#if AXIS_IS_TMC(X)
extern TMC_CLASS(X, X) stepperX;
#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_READ() stepperX.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(X)
#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;
#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_READ() stepperY.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Y)
#define Y_STEP_WRITE(STATE) do{ if (STATE) TOGGLE(Y_STEP_PIN); }while(0)
#endif
#endif
// Z Stepper
#if AXIS_IS_TMC(Z)
extern TMC_CLASS(Z, Z) stepperZ;
#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_READ() stepperZ.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z)
#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;
#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_READ() stepperX2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(X2)
#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;
#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_READ() stepperY2.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Y2)
#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)
#define Z2_ENABLE_INIT() NOOP
#define Z2_ENABLE_WRITE(STATE) stepperZ2.toff((STATE)==Z_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// Z3 Stepper
#if HAS_Z3_ENABLE && AXIS_IS_TMC(Z3)
extern TMC_CLASS(Z3, Z) stepperZ3;
#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_READ() stepperZ3.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z3)
#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;
#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_READ() stepperZ4.isEnabled()
#endif
#if AXIS_HAS_SQUARE_WAVE(Z4)
#define Z4_STEP_WRITE(STATE) do{ if(STATE) TOGGLE(Z4_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)
#define E0_ENABLE_INIT() NOOP
#define E0_ENABLE_WRITE(STATE) stepperE0.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E1 Stepper
#if AXIS_IS_TMC(E1)
extern TMC_CLASS_E(1) stepperE1;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E1)
#define E1_ENABLE_INIT() NOOP
#define E1_ENABLE_WRITE(STATE) stepperE1.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E2 Stepper
#if AXIS_IS_TMC(E2)
extern TMC_CLASS_E(2) stepperE2;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E2)
#define E2_ENABLE_INIT() NOOP
#define E2_ENABLE_WRITE(STATE) stepperE2.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E3 Stepper
#if AXIS_IS_TMC(E3)
extern TMC_CLASS_E(3) stepperE3;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E3)
#define E3_ENABLE_INIT() NOOP
#define E3_ENABLE_WRITE(STATE) stepperE3.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E4 Stepper
#if AXIS_IS_TMC(E4)
extern TMC_CLASS_E(4) stepperE4;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E4)
#define E4_ENABLE_INIT() NOOP
#define E4_ENABLE_WRITE(STATE) stepperE4.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E5 Stepper
#if AXIS_IS_TMC(E5)
extern TMC_CLASS_E(5) stepperE5;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E5)
#define E5_ENABLE_INIT() NOOP
#define E5_ENABLE_WRITE(STATE) stepperE5.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E6 Stepper
#if AXIS_IS_TMC(E6)
extern TMC_CLASS_E(6) stepperE6;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E6)
#define E6_ENABLE_INIT() NOOP
#define E6_ENABLE_WRITE(STATE) stepperE6.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif
// E7 Stepper
#if AXIS_IS_TMC(E7)
extern TMC_CLASS_E(7) stepperE7;
#if ENABLED(SOFTWARE_DRIVER_ENABLE) && AXIS_IS_TMC(E7)
#define E7_ENABLE_INIT() NOOP
#define E7_ENABLE_WRITE(STATE) stepperE7.toff((STATE)==E_ENABLE_ON ? chopper_timing.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)
#endif
#endif

3466
Marlin/src/module/temperature.cpp Executable file

File diff suppressed because it is too large Load Diff

903
Marlin/src/module/temperature.h Executable file
View File

@@ -0,0 +1,903 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* temperature.h - temperature controller
*/
#include "thermistor/thermistors.h"
#include "../inc/MarlinConfig.h"
#if ENABLED(AUTO_POWER_CONTROL)
#include "../feature/power.h"
#endif
#ifndef SOFT_PWM_SCALE
#define SOFT_PWM_SCALE 0
#endif
#if HOTENDS <= 1
#define HOTEND_INDEX 0
#define E_NAME
#else
#define HOTEND_INDEX e
#define E_NAME e
#endif
// Identifiers for other heaters
typedef enum : int8_t {
INDEX_NONE = -5,
H_PROBE, H_REDUNDANT, H_CHAMBER, H_BED,
H_E0, H_E1, H_E2, H_E3, H_E4, H_E5, H_E6, H_E7
} heater_ind_t;
// PID storage
typedef struct { float Kp, Ki, Kd; } PID_t;
typedef struct { float Kp, Ki, Kd, Kc; } PIDC_t;
typedef struct { float Kp, Ki, Kd, Kf; } PIDF_t;
typedef struct { float Kp, Ki, Kd, Kc, Kf; } PIDCF_t;
typedef
#if BOTH(PID_EXTRUSION_SCALING, PID_FAN_SCALING)
PIDCF_t
#elif ENABLED(PID_EXTRUSION_SCALING)
PIDC_t
#elif ENABLED(PID_FAN_SCALING)
PIDF_t
#else
PID_t
#endif
hotend_pid_t;
#if ENABLED(PID_EXTRUSION_SCALING)
typedef IF<(LPQ_MAX_LEN > 255), uint16_t, uint8_t>::type lpq_ptr_t;
#endif
#if ENABLED(PIDTEMP)
#define _PID_Kp(H) Temperature::temp_hotend[H].pid.Kp
#define _PID_Ki(H) Temperature::temp_hotend[H].pid.Ki
#define _PID_Kd(H) Temperature::temp_hotend[H].pid.Kd
#if ENABLED(PID_EXTRUSION_SCALING)
#define _PID_Kc(H) Temperature::temp_hotend[H].pid.Kc
#else
#define _PID_Kc(H) 1
#endif
#if ENABLED(PID_FAN_SCALING)
#define _PID_Kf(H) Temperature::temp_hotend[H].pid.Kf
#else
#define _PID_Kf(H) 0
#endif
#else
#define _PID_Kp(H) NAN
#define _PID_Ki(H) NAN
#define _PID_Kd(H) NAN
#define _PID_Kc(H) 1
#endif
#define PID_PARAM(F,H) _PID_##F(H)
/**
* States for ADC reading in the ISR
*/
enum ADCSensorState : char {
StartSampling,
#if HAS_TEMP_ADC_0
PrepareTemp_0, MeasureTemp_0,
#endif
#if HAS_HEATED_BED
PrepareTemp_BED, MeasureTemp_BED,
#endif
#if HAS_TEMP_CHAMBER
PrepareTemp_CHAMBER, MeasureTemp_CHAMBER,
#endif
#if HAS_TEMP_PROBE
PrepareTemp_PROBE, MeasureTemp_PROBE,
#endif
#if HAS_TEMP_ADC_1
PrepareTemp_1, MeasureTemp_1,
#endif
#if HAS_TEMP_ADC_2
PrepareTemp_2, MeasureTemp_2,
#endif
#if HAS_TEMP_ADC_3
PrepareTemp_3, MeasureTemp_3,
#endif
#if HAS_TEMP_ADC_4
PrepareTemp_4, MeasureTemp_4,
#endif
#if HAS_TEMP_ADC_5
PrepareTemp_5, MeasureTemp_5,
#endif
#if HAS_TEMP_ADC_6
PrepareTemp_6, MeasureTemp_6,
#endif
#if HAS_TEMP_ADC_7
PrepareTemp_7, MeasureTemp_7,
#endif
#if HAS_JOY_ADC_X
PrepareJoy_X, MeasureJoy_X,
#endif
#if HAS_JOY_ADC_Y
PrepareJoy_Y, MeasureJoy_Y,
#endif
#if HAS_JOY_ADC_Z
PrepareJoy_Z, MeasureJoy_Z,
#endif
#if ENABLED(FILAMENT_WIDTH_SENSOR)
Prepare_FILWIDTH, Measure_FILWIDTH,
#endif
#if HAS_ADC_BUTTONS
Prepare_ADC_KEY, Measure_ADC_KEY,
#endif
SensorsReady, // Temperatures ready. Delay the next round of readings to let ADC pins settle.
StartupDelay // Startup, delay initial temp reading a tiny bit so the hardware can settle
};
// Minimum number of Temperature::ISR loops between sensor readings.
// Multiplied by 16 (OVERSAMPLENR) to obtain the total time to
// get all oversampled sensor readings
#define MIN_ADC_ISR_LOOPS 10
#define ACTUAL_ADC_SAMPLES _MAX(int(MIN_ADC_ISR_LOOPS), int(SensorsReady))
#if HAS_PID_HEATING
#define PID_K2 (1-float(PID_K1))
#define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
// Apply the scale factors to the PID values
#define scalePID_i(i) ( float(i) * PID_dT )
#define unscalePID_i(i) ( float(i) / PID_dT )
#define scalePID_d(d) ( float(d) / PID_dT )
#define unscalePID_d(d) ( float(d) * PID_dT )
#endif
#define G26_CLICK_CAN_CANCEL (HAS_LCD_MENU && ENABLED(G26_MESH_VALIDATION))
// A temperature sensor
typedef struct TempInfo {
uint16_t acc;
int16_t raw;
float celsius;
inline void reset() { acc = 0; }
inline void sample(const uint16_t s) { acc += s; }
inline void update() { raw = acc; }
} temp_info_t;
// A PWM heater with temperature sensor
typedef struct HeaterInfo : public TempInfo {
int16_t target;
uint8_t soft_pwm_amount;
} heater_info_t;
// A heater with PID stabilization
template<typename T>
struct PIDHeaterInfo : public HeaterInfo {
T pid; // Initialized by settings.load()
};
#if ENABLED(PIDTEMP)
typedef struct PIDHeaterInfo<hotend_pid_t> hotend_info_t;
#else
typedef heater_info_t hotend_info_t;
#endif
#if HAS_HEATED_BED
#if ENABLED(PIDTEMPBED)
typedef struct PIDHeaterInfo<PID_t> bed_info_t;
#else
typedef heater_info_t bed_info_t;
#endif
#endif
#if HAS_TEMP_PROBE
typedef temp_info_t probe_info_t;
#endif
#if HAS_HEATED_CHAMBER
typedef heater_info_t chamber_info_t;
#elif HAS_TEMP_CHAMBER
typedef temp_info_t chamber_info_t;
#endif
// Heater idle handling
typedef struct {
millis_t timeout_ms;
bool timed_out;
inline void update(const millis_t &ms) { if (!timed_out && timeout_ms && ELAPSED(ms, timeout_ms)) timed_out = true; }
inline void start(const millis_t &ms) { timeout_ms = millis() + ms; timed_out = false; }
inline void reset() { timeout_ms = 0; timed_out = false; }
inline void expire() { start(0); }
} hotend_idle_t;
// Heater watch handling
template <int INCREASE, int HYSTERESIS, millis_t PERIOD>
struct HeaterWatch {
uint16_t target;
millis_t next_ms;
inline bool elapsed(const millis_t &ms) { return next_ms && ELAPSED(ms, next_ms); }
inline bool elapsed() { return elapsed(millis()); }
inline void restart(const int16_t curr, const int16_t tgt) {
if (tgt) {
const int16_t newtarget = curr + INCREASE;
if (newtarget < tgt - HYSTERESIS - 1) {
target = newtarget;
next_ms = millis() + PERIOD * 1000UL;
return;
}
}
next_ms = 0;
}
};
#if WATCH_HOTENDS
typedef struct HeaterWatch<WATCH_TEMP_INCREASE, TEMP_HYSTERESIS, WATCH_TEMP_PERIOD> hotend_watch_t;
#endif
#if WATCH_BED
typedef struct HeaterWatch<WATCH_BED_TEMP_INCREASE, TEMP_BED_HYSTERESIS, WATCH_BED_TEMP_PERIOD> bed_watch_t;
#endif
#if WATCH_CHAMBER
typedef struct HeaterWatch<WATCH_CHAMBER_TEMP_INCREASE, TEMP_CHAMBER_HYSTERESIS, WATCH_CHAMBER_TEMP_PERIOD> chamber_watch_t;
#endif
// Temperature sensor read value ranges
typedef struct { int16_t raw_min, raw_max; } raw_range_t;
typedef struct { int16_t mintemp, maxtemp; } celsius_range_t;
typedef struct { int16_t raw_min, raw_max, mintemp, maxtemp; } temp_range_t;
#define THERMISTOR_ABS_ZERO_C -273.15f // bbbbrrrrr cold !
#define THERMISTOR_RESISTANCE_NOMINAL_C 25.0f // mmmmm comfortable
#if HAS_USER_THERMISTORS
enum CustomThermistorIndex : uint8_t {
#if ENABLED(HEATER_0_USER_THERMISTOR)
CTI_HOTEND_0,
#endif
#if ENABLED(HEATER_1_USER_THERMISTOR)
CTI_HOTEND_1,
#endif
#if ENABLED(HEATER_2_USER_THERMISTOR)
CTI_HOTEND_2,
#endif
#if ENABLED(HEATER_3_USER_THERMISTOR)
CTI_HOTEND_3,
#endif
#if ENABLED(HEATER_4_USER_THERMISTOR)
CTI_HOTEND_4,
#endif
#if ENABLED(HEATER_5_USER_THERMISTOR)
CTI_HOTEND_5,
#endif
#if ENABLED(HEATER_BED_USER_THERMISTOR)
CTI_BED,
#endif
#if ENABLED(HEATER_PROBE_USER_THERMISTOR)
CTI_PROBE,
#endif
#if ENABLED(HEATER_CHAMBER_USER_THERMISTOR)
CTI_CHAMBER,
#endif
USER_THERMISTORS
};
// User-defined thermistor
typedef struct {
bool pre_calc; // true if pre-calculations update needed
float sh_c_coeff, // Steinhart-Hart C coefficient .. defaults to '0.0'
sh_alpha,
series_res,
res_25, res_25_recip,
res_25_log,
beta, beta_recip;
} user_thermistor_t;
#endif
class Temperature {
public:
#if HOTENDS
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
#define HOTEND_TEMPS (HOTENDS + 1)
#else
#define HOTEND_TEMPS HOTENDS
#endif
static hotend_info_t temp_hotend[HOTEND_TEMPS];
#endif
#if HAS_HEATED_BED
static bed_info_t temp_bed;
#endif
#if HAS_TEMP_PROBE
static probe_info_t temp_probe;
#endif
#if HAS_TEMP_CHAMBER
static chamber_info_t temp_chamber;
#endif
#if ENABLED(AUTO_POWER_E_FANS)
static uint8_t autofan_speed[HOTENDS];
#endif
#if ENABLED(AUTO_POWER_CHAMBER_FAN)
static uint8_t chamberfan_speed;
#endif
#if ENABLED(FAN_SOFT_PWM)
static uint8_t soft_pwm_amount_fan[FAN_COUNT],
soft_pwm_count_fan[FAN_COUNT];
#endif
#if ENABLED(PREVENT_COLD_EXTRUSION)
static bool allow_cold_extrude;
static int16_t extrude_min_temp;
FORCE_INLINE static bool tooCold(const int16_t temp) { return allow_cold_extrude ? false : temp < extrude_min_temp; }
FORCE_INLINE static bool tooColdToExtrude(const uint8_t E_NAME) {
return tooCold(degHotend(HOTEND_INDEX));
}
FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t E_NAME) {
return tooCold(degTargetHotend(HOTEND_INDEX));
}
#else
FORCE_INLINE static bool tooColdToExtrude(const uint8_t) { return false; }
FORCE_INLINE static bool targetTooColdToExtrude(const uint8_t) { return false; }
#endif
FORCE_INLINE static bool hotEnoughToExtrude(const uint8_t e) { return !tooColdToExtrude(e); }
FORCE_INLINE static bool targetHotEnoughToExtrude(const uint8_t e) { return !targetTooColdToExtrude(e); }
#if HEATER_IDLE_HANDLER
static hotend_idle_t hotend_idle[HOTENDS];
#if HAS_HEATED_BED
static hotend_idle_t bed_idle;
#endif
#if HAS_HEATED_CHAMBER
static hotend_idle_t chamber_idle;
#endif
#endif
private:
#if EARLY_WATCHDOG
static bool inited; // If temperature controller is running
#endif
static volatile bool raw_temps_ready;
#if WATCH_HOTENDS
static hotend_watch_t watch_hotend[HOTENDS];
#endif
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
static uint16_t redundant_temperature_raw;
static float redundant_temperature;
#endif
#if ENABLED(PID_EXTRUSION_SCALING)
static int32_t last_e_position, lpq[LPQ_MAX_LEN];
static lpq_ptr_t lpq_ptr;
#endif
#if HOTENDS
static temp_range_t temp_range[HOTENDS];
#endif
#if HAS_HEATED_BED
#if WATCH_BED
static bed_watch_t watch_bed;
#endif
#if DISABLED(PIDTEMPBED)
static millis_t next_bed_check_ms;
#endif
#ifdef BED_MINTEMP
static int16_t mintemp_raw_BED;
#endif
#ifdef BED_MAXTEMP
static int16_t maxtemp_raw_BED;
#endif
#endif
#if HAS_HEATED_CHAMBER
#if WATCH_CHAMBER
static chamber_watch_t watch_chamber;
#endif
static millis_t next_chamber_check_ms;
#ifdef CHAMBER_MINTEMP
static int16_t mintemp_raw_CHAMBER;
#endif
#ifdef CHAMBER_MAXTEMP
static int16_t maxtemp_raw_CHAMBER;
#endif
#endif
#ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
static uint8_t consecutive_low_temperature_error[HOTENDS];
#endif
#ifdef MILLISECONDS_PREHEAT_TIME
static millis_t preheat_end_time[HOTENDS];
#endif
#if HAS_AUTO_FAN
static millis_t next_auto_fan_check_ms;
#endif
#if ENABLED(PROBING_HEATERS_OFF)
static bool paused;
#endif
public:
#if HAS_ADC_BUTTONS
static uint32_t current_ADCKey_raw;
static uint8_t ADCKey_count;
#endif
#if ENABLED(PID_EXTRUSION_SCALING)
static int16_t lpq_len;
#endif
/**
* Instance Methods
*/
void init();
/**
* Static (class) methods
*/
#if HAS_USER_THERMISTORS
static user_thermistor_t user_thermistor[USER_THERMISTORS];
static void log_user_thermistor(const uint8_t t_index, const bool eprom=false);
static void reset_user_thermistors();
static float user_thermistor_to_deg_c(const uint8_t t_index, const int raw);
static bool set_pull_up_res(int8_t t_index, float value) {
//if (!WITHIN(t_index, 0, USER_THERMISTORS - 1)) return false;
if (!WITHIN(value, 1, 1000000)) return false;
user_thermistor[t_index].series_res = value;
return true;
}
static bool set_res25(int8_t t_index, float value) {
if (!WITHIN(value, 1, 10000000)) return false;
user_thermistor[t_index].res_25 = value;
user_thermistor[t_index].pre_calc = true;
return true;
}
static bool set_beta(int8_t t_index, float value) {
if (!WITHIN(value, 1, 1000000)) return false;
user_thermistor[t_index].beta = value;
user_thermistor[t_index].pre_calc = true;
return true;
}
static bool set_sh_coeff(int8_t t_index, float value) {
if (!WITHIN(value, -0.01f, 0.01f)) return false;
user_thermistor[t_index].sh_c_coeff = value;
user_thermistor[t_index].pre_calc = true;
return true;
}
#endif
#if HOTENDS
static float analog_to_celsius_hotend(const int raw, const uint8_t e);
#endif
#if HAS_HEATED_BED
static float analog_to_celsius_bed(const int raw);
#endif
#if HAS_TEMP_PROBE
static float analog_to_celsius_probe(const int raw);
#endif
#if HAS_TEMP_CHAMBER
static float analog_to_celsius_chamber(const int raw);
#endif
#if FAN_COUNT > 0
static uint8_t fan_speed[FAN_COUNT];
#define FANS_LOOP(I) LOOP_L_N(I, FAN_COUNT)
static void set_fan_speed(const uint8_t target, const uint16_t speed);
#if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
static bool fans_paused;
static uint8_t saved_fan_speed[FAN_COUNT];
#endif
static constexpr inline uint8_t fanPercent(const uint8_t speed) { return ui8_to_percent(speed); }
#if ENABLED(ADAPTIVE_FAN_SLOWING)
static uint8_t fan_speed_scaler[FAN_COUNT];
#endif
static inline uint8_t scaledFanSpeed(const uint8_t target, const uint8_t fs) {
UNUSED(target); // Potentially unused!
return (fs * uint16_t(
#if ENABLED(ADAPTIVE_FAN_SLOWING)
fan_speed_scaler[target]
#else
128
#endif
)) >> 7;
}
static inline uint8_t scaledFanSpeed(const uint8_t target) {
return scaledFanSpeed(target, fan_speed[target]);
}
#if ENABLED(EXTRA_FAN_SPEED)
static uint8_t old_fan_speed[FAN_COUNT], new_fan_speed[FAN_COUNT];
static void set_temp_fan_speed(const uint8_t fan, const uint16_t tmp_temp);
#endif
#if EITHER(PROBING_FANS_OFF, ADVANCED_PAUSE_FANS_PAUSE)
void set_fans_paused(const bool p);
#endif
#endif // FAN_COUNT > 0
static inline void zero_fan_speeds() {
#if FAN_COUNT > 0
FANS_LOOP(i) set_fan_speed(i, 0);
#endif
}
/**
* Called from the Temperature ISR
*/
static void readings_ready();
static void tick();
/**
* Call periodically to manage heaters
*/
static void manage_heater() _O2; // Added _O2 to work around a compiler error
/**
* Preheating hotends
*/
#ifdef MILLISECONDS_PREHEAT_TIME
static bool is_preheating(const uint8_t E_NAME) {
return preheat_end_time[HOTEND_INDEX] && PENDING(millis(), preheat_end_time[HOTEND_INDEX]);
}
static void start_preheat_time(const uint8_t E_NAME) {
preheat_end_time[HOTEND_INDEX] = millis() + MILLISECONDS_PREHEAT_TIME;
}
static void reset_preheat_time(const uint8_t E_NAME) {
preheat_end_time[HOTEND_INDEX] = 0;
}
#else
#define is_preheating(n) (false)
#endif
//high level conversion routines, for use outside of temperature.cpp
//inline so that there is no performance decrease.
//deg=degreeCelsius
FORCE_INLINE static float degHotend(const uint8_t E_NAME) {
return (0
#if HOTENDS
+ temp_hotend[HOTEND_INDEX].celsius
#endif
);
}
#if ENABLED(SHOW_TEMP_ADC_VALUES)
FORCE_INLINE static int16_t rawHotendTemp(const uint8_t E_NAME) {
return (0
#if HOTENDS
+ temp_hotend[HOTEND_INDEX].raw
#endif
);
}
#endif
FORCE_INLINE static int16_t degTargetHotend(const uint8_t E_NAME) {
return (0
#if HOTENDS
+ temp_hotend[HOTEND_INDEX].target
#endif
);
}
#if WATCH_HOTENDS
static void start_watching_hotend(const uint8_t e=0);
#else
static inline void start_watching_hotend(const uint8_t=0) {}
#endif
#if HOTENDS
static void setTargetHotend(const int16_t celsius, const uint8_t E_NAME) {
const uint8_t ee = HOTEND_INDEX;
#ifdef MILLISECONDS_PREHEAT_TIME
if (celsius == 0)
reset_preheat_time(ee);
else if (temp_hotend[ee].target == 0)
start_preheat_time(ee);
#endif
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
temp_hotend[ee].target = _MIN(celsius, temp_range[ee].maxtemp - 15);
start_watching_hotend(ee);
}
FORCE_INLINE static bool isHeatingHotend(const uint8_t E_NAME) {
return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].celsius;
}
FORCE_INLINE static bool isCoolingHotend(const uint8_t E_NAME) {
return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].celsius;
}
#if HAS_TEMP_HOTEND
static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
#if G26_CLICK_CAN_CANCEL
, const bool click_to_cancel=false
#endif
);
#endif
FORCE_INLINE static bool still_heating(const uint8_t e) {
return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
}
#endif // HOTENDS
#if HAS_HEATED_BED
#if ENABLED(SHOW_TEMP_ADC_VALUES)
FORCE_INLINE static int16_t rawBedTemp() { return temp_bed.raw; }
#endif
FORCE_INLINE static float degBed() { return temp_bed.celsius; }
FORCE_INLINE static int16_t degTargetBed() { return temp_bed.target; }
FORCE_INLINE static bool isHeatingBed() { return temp_bed.target > temp_bed.celsius; }
FORCE_INLINE static bool isCoolingBed() { return temp_bed.target < temp_bed.celsius; }
#if WATCH_BED
static void start_watching_bed();
#else
static inline void start_watching_bed() {}
#endif
static void setTargetBed(const int16_t celsius) {
#if ENABLED(AUTO_POWER_CONTROL)
powerManager.power_on();
#endif
temp_bed.target =
#ifdef BED_MAXTEMP
_MIN(celsius, BED_MAXTEMP - 10)
#else
celsius
#endif
;
start_watching_bed();
}
static bool wait_for_bed(const bool no_wait_for_cooling=true
#if G26_CLICK_CAN_CANCEL
, const bool click_to_cancel=false
#endif
);
static void wait_for_bed_heating();
#endif // HAS_HEATED_BED
#if HAS_TEMP_PROBE
#if ENABLED(SHOW_TEMP_ADC_VALUES)
FORCE_INLINE static int16_t rawProbeTemp() { return temp_probe.raw; }
#endif
FORCE_INLINE static float degProbe() { return temp_probe.celsius; }
#endif
#if WATCH_PROBE
static void start_watching_probe();
#else
static inline void start_watching_probe() {}
#endif
#if HAS_TEMP_CHAMBER
#if ENABLED(SHOW_TEMP_ADC_VALUES)
FORCE_INLINE static int16_t rawChamberTemp() { return temp_chamber.raw; }
#endif
FORCE_INLINE static float degChamber() { return temp_chamber.celsius; }
#if HAS_HEATED_CHAMBER
FORCE_INLINE static int16_t degTargetChamber() { return temp_chamber.target; }
FORCE_INLINE static bool isHeatingChamber() { return temp_chamber.target > temp_chamber.celsius; }
FORCE_INLINE static bool isCoolingChamber() { return temp_chamber.target < temp_chamber.celsius; }
static bool wait_for_chamber(const bool no_wait_for_cooling=true);
#endif
#endif // HAS_TEMP_CHAMBER
#if WATCH_CHAMBER
static void start_watching_chamber();
#else
static inline void start_watching_chamber() {}
#endif
#if HAS_HEATED_CHAMBER
static void setTargetChamber(const int16_t celsius) {
temp_chamber.target =
#ifdef CHAMBER_MAXTEMP
_MIN(celsius, CHAMBER_MAXTEMP - 10)
#else
celsius
#endif
;
start_watching_chamber();
}
#endif // HAS_HEATED_CHAMBER
/**
* The software PWM power for a heater
*/
static int16_t getHeaterPower(const heater_ind_t heater);
/**
* Switch off all heaters, set all target temperatures to 0
*/
static void disable_all_heaters();
#if ENABLED(PRINTJOB_TIMER_AUTOSTART)
/**
* Methods to check if heaters are enabled, indicating an active job
*/
static bool over_autostart_threshold();
static void check_timer_autostart(const bool can_start, const bool can_stop);
#endif
/**
* Perform auto-tuning for hotend or bed in response to M303
*/
#if HAS_PID_HEATING
static void PID_autotune(const float &target, const heater_ind_t hotend, const int8_t ncycles, const bool set_result=false);
#if ENABLED(NO_FAN_SLOWING_IN_PID_TUNING)
static bool adaptive_fan_slowing;
#elif ENABLED(ADAPTIVE_FAN_SLOWING)
static constexpr bool adaptive_fan_slowing = true;
#endif
/**
* Update the temp manager when PID values change
*/
#if ENABLED(PIDTEMP)
FORCE_INLINE static void updatePID() {
#if ENABLED(PID_EXTRUSION_SCALING)
last_e_position = 0;
#endif
}
#endif
#endif
#if ENABLED(PROBING_HEATERS_OFF)
static void pause(const bool p);
FORCE_INLINE static bool is_paused() { return paused; }
#endif
#if HEATER_IDLE_HANDLER
static void reset_hotend_idle_timer(const uint8_t E_NAME) {
hotend_idle[HOTEND_INDEX].reset();
start_watching_hotend(HOTEND_INDEX);
}
#if HAS_HEATED_BED
static void reset_bed_idle_timer() {
bed_idle.reset();
start_watching_bed();
}
#endif
#endif // HEATER_IDLE_HANDLER
#if HAS_TEMP_SENSOR
static void print_heater_states(const uint8_t target_extruder
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
, const bool include_r=false
#endif
);
#if ENABLED(AUTO_REPORT_TEMPERATURES)
static uint8_t auto_report_temp_interval;
static millis_t next_temp_report_ms;
static void auto_report_temperatures();
static inline void set_auto_report_interval(uint8_t v) {
NOMORE(v, 60);
auto_report_temp_interval = v;
next_temp_report_ms = millis() + 1000UL * v;
}
#endif
#endif
#if HAS_DISPLAY
static void set_heating_message(const uint8_t e);
#endif
private:
static void update_raw_temperatures();
static void updateTemperaturesFromRawValues();
#define HAS_MAX6675 EITHER(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
#if HAS_MAX6675
#if BOTH(HEATER_0_USES_MAX6675, HEATER_1_USES_MAX6675)
#define COUNT_6675 2
#else
#define COUNT_6675 1
#endif
#if COUNT_6675 > 1
#define READ_MAX6675(N) read_max6675(N)
#else
#define READ_MAX6675(N) read_max6675()
#endif
static int read_max6675(
#if COUNT_6675 > 1
const uint8_t hindex=0
#endif
);
#endif
static void checkExtruderAutoFans();
static float get_pid_output_hotend(const uint8_t e);
#if ENABLED(PIDTEMPBED)
static float get_pid_output_bed();
#endif
#if HAS_HEATED_CHAMBER
static float get_pid_output_chamber();
#endif
static void _temp_error(const heater_ind_t e, PGM_P const serial_msg, PGM_P const lcd_msg);
static void min_temp_error(const heater_ind_t e);
static void max_temp_error(const heater_ind_t e);
#define HAS_THERMAL_PROTECTION (EITHER(THERMAL_PROTECTION_HOTENDS, THERMAL_PROTECTION_CHAMBER) || HAS_THERMALLY_PROTECTED_BED)
#if HAS_THERMAL_PROTECTION
enum TRState : char { TRInactive, TRFirstHeating, TRStable, TRRunaway };
typedef struct {
millis_t timer = 0;
TRState state = TRInactive;
} tr_state_machine_t;
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
static tr_state_machine_t tr_state_machine[HOTENDS];
#endif
#if HAS_THERMALLY_PROTECTED_BED
static tr_state_machine_t tr_state_machine_bed;
#endif
#if ENABLED(THERMAL_PROTECTION_CHAMBER)
static tr_state_machine_t tr_state_machine_chamber;
#endif
static void thermal_runaway_protection(tr_state_machine_t &state, const float &current, const float &target, const heater_ind_t heater_id, const uint16_t period_seconds, const uint16_t hysteresis_degc);
#endif // HAS_THERMAL_PROTECTION
};
extern Temperature thermalManager;

View File

@@ -0,0 +1,90 @@
/**
* 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 <http://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 = {
{ OV( 23), 300 },
{ OV( 25), 295 },
{ OV( 27), 290 },
{ OV( 28), 285 },
{ OV( 31), 280 },
{ OV( 33), 275 },
{ OV( 35), 270 },
{ OV( 38), 265 },
{ OV( 41), 260 },
{ OV( 44), 255 },
{ OV( 48), 250 },
{ OV( 52), 245 },
{ OV( 56), 240 },
{ OV( 61), 235 },
{ OV( 66), 230 },
{ OV( 71), 225 },
{ OV( 78), 220 },
{ OV( 84), 215 },
{ OV( 92), 210 },
{ OV( 100), 205 },
{ OV( 109), 200 },
{ OV( 120), 195 },
{ OV( 131), 190 },
{ OV( 143), 185 },
{ OV( 156), 180 },
{ OV( 171), 175 },
{ OV( 187), 170 },
{ OV( 205), 165 },
{ OV( 224), 160 },
{ OV( 245), 155 },
{ OV( 268), 150 },
{ OV( 293), 145 },
{ OV( 320), 140 },
{ OV( 348), 135 },
{ OV( 379), 130 },
{ OV( 411), 125 },
{ OV( 445), 120 },
{ OV( 480), 115 },
{ OV( 516), 110 },
{ OV( 553), 105 },
{ OV( 591), 100 },
{ OV( 628), 95 },
{ OV( 665), 90 },
{ OV( 702), 85 },
{ OV( 737), 80 },
{ OV( 770), 75 },
{ OV( 801), 70 },
{ OV( 830), 65 },
{ OV( 857), 60 },
{ OV( 881), 55 },
{ OV( 903), 50 },
{ OV( 922), 45 },
{ OV( 939), 40 },
{ OV( 954), 35 },
{ OV( 966), 30 },
{ OV( 977), 25 },
{ OV( 985), 20 },
{ OV( 993), 15 },
{ OV( 999), 10 },
{ OV(1004), 5 },
{ OV(1008), 0 },
{ OV(1012), -5 },
{ OV(1016), -10 },
{ OV(1020), -15 }
};

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 <http://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 = {
{ OV( 1), 929 },
{ OV( 36), 299 },
{ OV( 71), 246 },
{ OV( 106), 217 },
{ OV( 141), 198 },
{ OV( 176), 184 },
{ OV( 211), 173 },
{ OV( 246), 163 },
{ OV( 281), 154 },
{ OV( 316), 147 },
{ OV( 351), 140 },
{ OV( 386), 134 },
{ OV( 421), 128 },
{ OV( 456), 122 },
{ OV( 491), 117 },
{ OV( 526), 112 },
{ OV( 561), 107 },
{ OV( 596), 102 },
{ OV( 631), 97 },
{ OV( 666), 91 },
{ OV( 701), 86 },
{ OV( 736), 81 },
{ OV( 771), 76 },
{ OV( 806), 70 },
{ OV( 841), 63 },
{ OV( 876), 56 },
{ OV( 911), 48 },
{ OV( 946), 38 },
{ OV( 981), 23 },
{ OV(1005), 5 },
{ OV(1016), 0 }
};

View File

@@ -0,0 +1,39 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// Pt1000 with 1k0 pullup
const short temptable_1010[][2] PROGMEM = {
PtLine( 0, 1000, 1000),
PtLine( 25, 1000, 1000),
PtLine( 50, 1000, 1000),
PtLine( 75, 1000, 1000),
PtLine(100, 1000, 1000),
PtLine(125, 1000, 1000),
PtLine(150, 1000, 1000),
PtLine(175, 1000, 1000),
PtLine(200, 1000, 1000),
PtLine(225, 1000, 1000),
PtLine(250, 1000, 1000),
PtLine(275, 1000, 1000),
PtLine(300, 1000, 1000)
};

View File

@@ -0,0 +1,34 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// Pt1000 with 4k7 pullup
const short temptable_1047[][2] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 1000, 4700),
PtLine( 50, 1000, 4700),
PtLine(100, 1000, 4700),
PtLine(150, 1000, 4700),
PtLine(200, 1000, 4700),
PtLine(250, 1000, 4700),
PtLine(300, 1000, 4700)
};

View File

@@ -0,0 +1,76 @@
/**
* 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 <http://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 = {
{ OV( 1), 938 },
{ 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( 221), 170 },
{ OV( 241), 165 },
{ OV( 261), 160 },
{ OV( 281), 155 },
{ OV( 301), 150 },
{ OV( 331), 144 },
{ OV( 361), 139 },
{ OV( 391), 133 },
{ OV( 421), 128 },
{ OV( 451), 123 },
{ OV( 491), 117 },
{ OV( 531), 111 },
{ OV( 571), 105 },
{ OV( 611), 100 },
{ OV( 641), 95 },
{ OV( 681), 90 },
{ OV( 711), 85 },
{ OV( 751), 79 },
{ OV( 791), 72 },
{ OV( 811), 69 },
{ OV( 831), 65 },
{ OV( 871), 57 },
{ OV( 881), 55 },
{ OV( 901), 51 },
{ OV( 921), 45 },
{ OV( 941), 39 },
{ OV( 971), 28 },
{ OV( 981), 23 },
{ OV( 991), 17 },
{ OV(1001), 9 },
{ OV(1021), -27 }
};

View File

@@ -0,0 +1,34 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// Pt100 with 1k0 pullup
const short temptable_110[][2] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 100, 1000),
PtLine( 50, 100, 1000),
PtLine(100, 100, 1000),
PtLine(150, 100, 1000),
PtLine(200, 100, 1000),
PtLine(250, 100, 1000),
PtLine(300, 100, 1000)
};

View File

@@ -0,0 +1,56 @@
/**
* 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 <http://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 = {
{ OV( 35), 180 }, // top rating 180C
{ OV( 211), 140 },
{ OV( 233), 135 },
{ OV( 261), 130 },
{ OV( 290), 125 },
{ OV( 328), 120 },
{ OV( 362), 115 },
{ OV( 406), 110 },
{ OV( 446), 105 },
{ OV( 496), 100 },
{ OV( 539), 95 },
{ OV( 585), 90 },
{ OV( 629), 85 },
{ OV( 675), 80 },
{ OV( 718), 75 },
{ OV( 758), 70 },
{ OV( 793), 65 },
{ OV( 822), 60 },
{ OV( 841), 55 },
{ OV( 875), 50 },
{ OV( 899), 45 },
{ OV( 926), 40 },
{ OV( 946), 35 },
{ OV( 962), 30 },
{ OV( 977), 25 },
{ OV( 987), 20 },
{ OV( 995), 15 },
{ OV(1001), 10 },
{ OV(1010), 0 },
{ OV(1023), -40 }
};

View File

@@ -0,0 +1,49 @@
/**
* 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 <http://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 = {
{ OV( 20.04), 300 },
{ OV( 23.19), 290 },
{ OV( 26.71), 280 },
{ OV( 31.23), 270 },
{ OV( 36.52), 260 },
{ OV( 42.75), 250 },
{ OV( 50.68), 240 },
{ OV( 60.22), 230 },
{ OV( 72.03), 220 },
{ OV( 86.84), 210 },
{ OV(102.79), 200 },
{ OV(124.46), 190 },
{ OV(151.02), 180 },
{ OV(182.86), 170 },
{ OV(220.72), 160 },
{ OV(316.96), 140 },
{ OV(447.17), 120 },
{ OV(590.61), 100 },
{ OV(737.31), 80 },
{ OV(857.77), 60 },
{ OV(939.52), 40 },
{ OV(986.03), 20 },
{ OV(1008.7), 0 }
};

View File

@@ -0,0 +1,34 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// Pt100 with 4k7 pullup
const short temptable_147[][2] PROGMEM = {
// only a few values are needed as the curve is very flat
PtLine( 0, 100, 4700),
PtLine( 50, 100, 4700),
PtLine(100, 100, 4700),
PtLine(150, 100, 4700),
PtLine(200, 100, 4700),
PtLine(250, 100, 4700),
PtLine(300, 100, 4700)
};

View File

@@ -0,0 +1,65 @@
/**
* 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 <http://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 = {
{ OV( 31), 275 },
{ OV( 33), 270 },
{ OV( 35), 260 },
{ OV( 38), 253 },
{ OV( 41), 248 },
{ OV( 48), 239 },
{ OV( 56), 232 },
{ OV( 66), 222 },
{ OV( 78), 212 },
{ OV( 93), 206 },
{ OV( 106), 199 },
{ OV( 118), 191 },
{ OV( 130), 186 },
{ OV( 158), 176 },
{ OV( 187), 167 },
{ OV( 224), 158 },
{ OV( 270), 148 },
{ OV( 321), 137 },
{ OV( 379), 127 },
{ OV( 446), 117 },
{ OV( 518), 106 },
{ OV( 593), 96 },
{ OV( 668), 86 },
{ OV( 739), 76 },
{ OV( 767), 72 },
{ OV( 830), 62 },
{ OV( 902), 48 },
{ OV( 926), 45 },
{ OV( 955), 35 },
{ OV( 966), 30 },
{ OV( 977), 25 },
{ OV( 985), 20 },
{ OV( 993), 15 },
{ OV( 999), 10 },
{ OV(1004), 5 },
{ OV(1008), 0 },
{ OV(1012), -5 },
{ OV(1016), -10 },
{ OV(1020), -15 }
};

View File

@@ -0,0 +1,59 @@
/**
* 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 <http://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 = {
{ OV( 1), 713 },
{ OV( 17), 284 },
{ OV( 20), 275 },
{ OV( 23), 267 },
{ OV( 27), 257 },
{ OV( 31), 250 },
{ OV( 37), 240 },
{ OV( 43), 232 },
{ OV( 51), 222 },
{ OV( 61), 213 },
{ OV( 73), 204 },
{ OV( 87), 195 },
{ OV( 106), 185 },
{ OV( 128), 175 },
{ OV( 155), 166 },
{ OV( 189), 156 },
{ OV( 230), 146 },
{ OV( 278), 137 },
{ OV( 336), 127 },
{ OV( 402), 117 },
{ OV( 476), 107 },
{ OV( 554), 97 },
{ OV( 635), 87 },
{ OV( 713), 78 },
{ OV( 784), 68 },
{ OV( 846), 58 },
{ OV( 897), 49 },
{ OV( 937), 39 },
{ OV( 966), 30 },
{ OV( 986), 20 },
{ OV(1000), 10 },
{ OV(1010), 0 },
{ OV(1024),-273 } // for safety
};

View File

@@ -0,0 +1,62 @@
/**
* 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 <http://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
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
//
const short temptable_2[][2] PROGMEM = {
{ OV( 1), 848 },
{ OV( 30), 300 }, // top rating 300C
{ OV( 34), 290 },
{ OV( 39), 280 },
{ OV( 46), 270 },
{ OV( 53), 260 },
{ OV( 63), 250 },
{ OV( 74), 240 },
{ OV( 87), 230 },
{ OV( 104), 220 },
{ OV( 124), 210 },
{ OV( 148), 200 },
{ OV( 176), 190 },
{ OV( 211), 180 },
{ OV( 252), 170 },
{ OV( 301), 160 },
{ OV( 357), 150 },
{ OV( 420), 140 },
{ OV( 489), 130 },
{ OV( 562), 120 },
{ OV( 636), 110 },
{ OV( 708), 100 },
{ OV( 775), 90 },
{ OV( 835), 80 },
{ OV( 884), 70 },
{ OV( 924), 60 },
{ OV( 955), 50 },
{ OV( 977), 40 },
{ OV( 993), 30 },
{ OV(1004), 20 },
{ OV(1012), 10 },
{ OV(1016), 0 }
};

View File

@@ -0,0 +1,77 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
// Pt100 with INA826 amp on Ultimaker v2.0 electronics
const short temptable_20[][2] PROGMEM = {
{ OV( 0), 0 },
{ OV(227), 1 },
{ OV(236), 10 },
{ OV(245), 20 },
{ OV(253), 30 },
{ OV(262), 40 },
{ OV(270), 50 },
{ OV(279), 60 },
{ OV(287), 70 },
{ OV(295), 80 },
{ OV(304), 90 },
{ OV(312), 100 },
{ OV(320), 110 },
{ OV(329), 120 },
{ OV(337), 130 },
{ OV(345), 140 },
{ OV(353), 150 },
{ OV(361), 160 },
{ OV(369), 170 },
{ OV(377), 180 },
{ OV(385), 190 },
{ OV(393), 200 },
{ OV(401), 210 },
{ OV(409), 220 },
{ OV(417), 230 },
{ OV(424), 240 },
{ OV(432), 250 },
{ OV(440), 260 },
{ OV(447), 270 },
{ OV(455), 280 },
{ OV(463), 290 },
{ OV(470), 300 },
{ OV(478), 310 },
{ OV(485), 320 },
{ OV(493), 330 },
{ OV(500), 340 },
{ OV(507), 350 },
{ OV(515), 360 },
{ OV(522), 370 },
{ OV(529), 380 },
{ OV(537), 390 },
{ OV(544), 400 },
{ OV(614), 500 },
{ OV(681), 600 },
{ OV(744), 700 },
{ OV(805), 800 },
{ OV(862), 900 },
{ OV(917), 1000 },
{ OV(968), 1100 }
};

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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
// Pt100 with LMV324 amp on Overlord v1.1 electronics
const short temptable_201[][2] PROGMEM = {
{ OV( 0), 0 },
{ OV( 8), 1 },
{ OV( 23), 6 },
{ OV( 41), 15 },
{ OV( 51), 20 },
{ OV( 68), 28 },
{ OV( 74), 30 },
{ OV( 88), 35 },
{ OV( 99), 40 },
{ OV( 123), 50 },
{ OV( 148), 60 },
{ OV( 173), 70 },
{ OV( 198), 80 },
{ OV( 221), 90 },
{ OV( 245), 100 },
{ OV( 269), 110 },
{ OV( 294), 120 },
{ OV( 316), 130 },
{ OV( 342), 140 },
{ OV( 364), 150 },
{ OV( 387), 160 },
{ OV( 412), 170 },
{ OV( 433), 180 },
{ OV( 456), 190 },
{ OV( 480), 200 },
{ OV( 500), 210 },
{ OV( 548), 224 },
{ OV( 572), 233 },
{ OV(1155), 490 }
};

View File

@@ -0,0 +1,69 @@
//
// Unknown 200K thermistor on a Copymaster 3D hotend
// Temptable sent from dealer technologyoutlet.co.uk
//
const short temptable_202[][2] PROGMEM = {
{ OV( 1), 864 },
{ OV( 35), 300 },
{ OV( 38), 295 },
{ OV( 41), 290 },
{ OV( 44), 285 },
{ OV( 47), 280 },
{ OV( 51), 275 },
{ OV( 55), 270 },
{ OV( 60), 265 },
{ OV( 65), 260 },
{ OV( 70), 255 },
{ OV( 76), 250 },
{ OV( 83), 245 },
{ OV( 90), 240 },
{ OV( 98), 235 },
{ OV( 107), 230 },
{ OV( 116), 225 },
{ OV( 127), 220 },
{ OV( 138), 215 },
{ OV( 151), 210 },
{ OV( 164), 205 },
{ OV( 179), 200 },
{ OV( 195), 195 },
{ OV( 213), 190 },
{ OV( 232), 185 },
{ OV( 253), 180 },
{ OV( 275), 175 },
{ OV( 299), 170 },
{ OV( 325), 165 },
{ OV( 352), 160 },
{ OV( 381), 155 },
{ OV( 411), 150 },
{ OV( 443), 145 },
{ OV( 476), 140 },
{ OV( 511), 135 },
{ OV( 546), 130 },
{ OV( 581), 125 },
{ OV( 617), 120 },
{ OV( 652), 115 },
{ OV( 687), 110 },
{ OV( 720), 105 },
{ OV( 753), 100 },
{ OV( 783), 95 },
{ OV( 812), 90 },
{ OV( 839), 85 },
{ OV( 864), 80 },
{ OV( 886), 75 },
{ OV( 906), 70 },
{ OV( 924), 65 },
{ OV( 940), 60 },
{ OV( 954), 55 },
{ OV( 966), 50 },
{ OV( 976), 45 },
{ OV( 985), 40 },
{ OV( 992), 35 },
{ OV( 998), 30 },
{ OV(1003), 25 },
{ OV(1007), 20 },
{ OV(1011), 15 },
{ OV(1014), 10 },
{ OV(1016), 5 },
{ OV(1018), 0 }
};

View File

@@ -0,0 +1,77 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#define REVERSE_TEMP_SENSOR_RANGE
#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 = {
{ OV( 0), 0 },
{ OV(227), 1 },
{ OV(236), 10 },
{ OV(245), 20 },
{ OV(253), 30 },
{ OV(262), 40 },
{ OV(270), 50 },
{ OV(279), 60 },
{ OV(287), 70 },
{ OV(295), 80 },
{ OV(304), 90 },
{ OV(312), 100 },
{ OV(320), 110 },
{ OV(329), 120 },
{ OV(337), 130 },
{ OV(345), 140 },
{ OV(353), 150 },
{ OV(361), 160 },
{ OV(369), 170 },
{ OV(377), 180 },
{ OV(385), 190 },
{ OV(393), 200 },
{ OV(401), 210 },
{ OV(409), 220 },
{ OV(417), 230 },
{ OV(424), 240 },
{ OV(432), 250 },
{ OV(440), 260 },
{ OV(447), 270 },
{ OV(455), 280 },
{ OV(463), 290 },
{ OV(470), 300 },
{ OV(478), 310 },
{ OV(485), 320 },
{ OV(493), 330 },
{ OV(500), 340 },
{ OV(507), 350 },
{ OV(515), 360 },
{ OV(522), 370 },
{ OV(529), 380 },
{ OV(537), 390 },
{ OV(544), 400 },
{ OV(614), 500 }
};
#undef OV_SCALE
#define OV_SCALE(N) (N)

View File

@@ -0,0 +1,54 @@
/**
* 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 <http://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 = {
{ OV( 1), 864 },
{ OV( 21), 300 },
{ OV( 25), 290 },
{ OV( 29), 280 },
{ OV( 33), 270 },
{ OV( 39), 260 },
{ OV( 46), 250 },
{ OV( 54), 240 },
{ OV( 64), 230 },
{ OV( 75), 220 },
{ OV( 90), 210 },
{ OV( 107), 200 },
{ OV( 128), 190 },
{ OV( 154), 180 },
{ OV( 184), 170 },
{ OV( 221), 160 },
{ OV( 265), 150 },
{ OV( 316), 140 },
{ OV( 375), 130 },
{ OV( 441), 120 },
{ OV( 513), 110 },
{ OV( 588), 100 },
{ OV( 734), 80 },
{ OV( 856), 60 },
{ OV( 938), 40 },
{ OV( 986), 20 },
{ OV(1008), 0 },
{ OV(1018), -20 }
};

View File

@@ -0,0 +1,92 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#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 = {
{ OVM( 23), 300 },
{ OVM( 25), 295 },
{ OVM( 27), 290 },
{ OVM( 28), 285 },
{ OVM( 31), 280 },
{ OVM( 33), 275 },
{ OVM( 35), 270 },
{ OVM( 38), 265 },
{ OVM( 41), 260 },
{ OVM( 44), 255 },
{ OVM( 48), 250 },
{ OVM( 52), 245 },
{ OVM( 56), 240 },
{ OVM( 61), 235 },
{ OVM( 66), 230 },
{ OVM( 71), 225 },
{ OVM( 78), 220 },
{ OVM( 84), 215 },
{ OVM( 92), 210 },
{ OVM( 100), 205 },
{ OVM( 109), 200 },
{ OVM( 120), 195 },
{ OVM( 131), 190 },
{ OVM( 143), 185 },
{ OVM( 156), 180 },
{ OVM( 171), 175 },
{ OVM( 187), 170 },
{ OVM( 205), 165 },
{ OVM( 224), 160 },
{ OVM( 245), 155 },
{ OVM( 268), 150 },
{ OVM( 293), 145 },
{ OVM( 320), 140 },
{ OVM( 348), 135 },
{ OVM( 379), 130 },
{ OVM( 411), 125 },
{ OVM( 445), 120 },
{ OVM( 480), 115 },
{ OVM( 516), 110 },
{ OVM( 553), 105 },
{ OVM( 591), 100 },
{ OVM( 628), 95 },
{ OVM( 665), 90 },
{ OVM( 702), 85 },
{ OVM( 737), 80 },
{ OVM( 770), 75 },
{ OVM( 801), 70 },
{ OVM( 830), 65 },
{ OVM( 857), 60 },
{ OVM( 881), 55 },
{ OVM( 903), 50 },
{ OVM( 922), 45 },
{ OVM( 939), 40 },
{ OVM( 954), 35 },
{ OVM( 966), 30 },
{ OVM( 977), 25 },
{ OVM( 985), 20 },
{ OVM( 993), 15 },
{ OVM( 999), 10 },
{ OVM(1004), 5 },
{ OVM(1008), 0 },
{ OVM(1012), -5 },
{ OVM(1016), -10 },
{ OVM(1020), -15 }
};

View File

@@ -0,0 +1,50 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#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 = {
{ OVM( 268), 150 },
{ OVM( 293), 145 },
{ OVM( 320), 141 },
{ OVM( 379), 133 },
{ OVM( 445), 122 },
{ OVM( 516), 108 },
{ OVM( 591), 98 },
{ OVM( 665), 88 },
{ OVM( 737), 79 },
{ OVM( 801), 70 },
{ OVM( 857), 55 },
{ OVM( 903), 46 },
{ OVM( 939), 39 },
{ OVM( 954), 33 },
{ OVM( 966), 27 },
{ OVM( 977), 22 },
{ OVM( 999), 15 },
{ OVM(1004), 5 },
{ OVM(1008), 0 },
{ OVM(1012), -5 },
{ OVM(1016), -10 },
{ OVM(1020), -15 }
};

View File

@@ -0,0 +1,46 @@
/**
* 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 <http://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 = {
{ OV( 1), 430 },
{ OV( 54), 137 },
{ OV( 107), 107 },
{ OV( 160), 91 },
{ OV( 213), 80 },
{ OV( 266), 71 },
{ OV( 319), 64 },
{ OV( 372), 57 },
{ OV( 425), 51 },
{ OV( 478), 46 },
{ OV( 531), 41 },
{ OV( 584), 35 },
{ OV( 637), 30 },
{ OV( 690), 25 },
{ OV( 743), 20 },
{ OV( 796), 14 },
{ OV( 849), 7 },
{ OV( 902), 0 },
{ OV( 955), -11 },
{ OV(1008), -35 }
};

View File

@@ -0,0 +1,62 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// 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
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
const short temptable_5[][2] PROGMEM = {
{ OV( 1), 713 },
{ OV( 17), 300 }, // top rating 300C
{ OV( 20), 290 },
{ OV( 23), 280 },
{ OV( 27), 270 },
{ OV( 31), 260 },
{ OV( 37), 250 },
{ OV( 43), 240 },
{ OV( 51), 230 },
{ OV( 61), 220 },
{ OV( 73), 210 },
{ OV( 87), 200 },
{ OV( 106), 190 },
{ OV( 128), 180 },
{ OV( 155), 170 },
{ OV( 189), 160 },
{ OV( 230), 150 },
{ OV( 278), 140 },
{ OV( 336), 130 },
{ OV( 402), 120 },
{ OV( 476), 110 },
{ OV( 554), 100 },
{ OV( 635), 90 },
{ OV( 713), 80 },
{ OV( 784), 70 },
{ OV( 846), 60 },
{ OV( 897), 50 },
{ OV( 937), 40 },
{ OV( 966), 30 },
{ OV( 986), 20 },
{ OV(1000), 10 },
{ OV(1010), 0 }
};

View File

@@ -0,0 +1,58 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// 100k Zonestar thermistor. Adjusted By Hally
const short temptable_501[][2] PROGMEM = {
{ OV( 1), 713 },
{ OV( 14), 300 }, // Top rating 300C
{ OV( 16), 290 },
{ OV( 19), 280 },
{ OV( 23), 270 },
{ OV( 27), 260 },
{ OV( 31), 250 },
{ OV( 37), 240 },
{ OV( 47), 230 },
{ OV( 57), 220 },
{ OV( 68), 210 },
{ OV( 84), 200 },
{ OV( 100), 190 },
{ OV( 128), 180 },
{ OV( 155), 170 },
{ OV( 189), 160 },
{ OV( 230), 150 },
{ OV( 278), 140 },
{ OV( 336), 130 },
{ OV( 402), 120 },
{ OV( 476), 110 },
{ OV( 554), 100 },
{ OV( 635), 90 },
{ OV( 713), 80 },
{ OV( 784), 70 },
{ OV( 846), 60 },
{ OV( 897), 50 },
{ OV( 937), 40 },
{ OV( 966), 30 },
{ OV( 986), 20 },
{ OV(1000), 10 },
{ OV(1010), 0 }
};

View File

@@ -0,0 +1,83 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 4092 K, 1 kOhm pull-up,
// 100k EPCOS (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// 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 = {
{ OV( 1), 350 },
{ OV( 190), 250 }, // top rating 250C
{ OV( 203), 245 },
{ OV( 217), 240 },
{ OV( 232), 235 },
{ OV( 248), 230 },
{ OV( 265), 225 },
{ OV( 283), 220 },
{ OV( 302), 215 },
{ OV( 322), 210 },
{ OV( 344), 205 },
{ OV( 366), 200 },
{ OV( 390), 195 },
{ OV( 415), 190 },
{ OV( 440), 185 },
{ OV( 467), 180 },
{ OV( 494), 175 },
{ OV( 522), 170 },
{ OV( 551), 165 },
{ OV( 580), 160 },
{ OV( 609), 155 },
{ OV( 638), 150 },
{ OV( 666), 145 },
{ OV( 695), 140 },
{ OV( 722), 135 },
{ OV( 749), 130 },
{ OV( 775), 125 },
{ OV( 800), 120 },
{ OV( 823), 115 },
{ OV( 845), 110 },
{ OV( 865), 105 },
{ OV( 884), 100 },
{ OV( 901), 95 },
{ OV( 917), 90 },
{ OV( 932), 85 },
{ OV( 944), 80 },
{ OV( 956), 75 },
{ OV( 966), 70 },
{ OV( 975), 65 },
{ OV( 982), 60 },
{ OV( 989), 55 },
{ OV( 995), 50 },
{ OV(1000), 45 },
{ OV(1004), 40 },
{ OV(1007), 35 },
{ OV(1010), 30 },
{ OV(1013), 25 },
{ OV(1015), 20 },
{ OV(1017), 15 },
{ OV(1018), 10 },
{ OV(1019), 5 },
{ OV(1020), 0 },
{ OV(1021), -5 }
};

View File

@@ -0,0 +1,87 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
// 100k thermistor supplied with RPW-Ultra hotend, 4.7k pullup
const short temptable_512[][2] PROGMEM = {
{ OV(26), 300 },
{ OV(28), 295 },
{ OV(30), 290 },
{ OV(32), 285 },
{ OV(34), 280 },
{ OV(37), 275 },
{ OV(39), 270 },
{ OV(42), 265 },
{ OV(46), 260 },
{ OV(49), 255 },
{ OV(53), 250 }, // 256.5
{ OV(57), 245 },
{ OV(62), 240 },
{ OV(67), 235 },
{ OV(73), 230 },
{ OV(79), 225 },
{ OV(86), 220 },
{ OV(94), 215 },
{ OV(103), 210 },
{ OV(112), 205 },
{ OV(123), 200 },
{ OV(135), 195 },
{ OV(148), 190 },
{ OV(162), 185 },
{ OV(178), 180 },
{ OV(195), 175 },
{ OV(215), 170 },
{ OV(235), 165 },
{ OV(258), 160 },
{ OV(283), 155 },
{ OV(310), 150 }, // 2040.6
{ OV(338), 145 },
{ OV(369), 140 },
{ OV(401), 135 },
{ OV(435), 130 },
{ OV(470), 125 },
{ OV(505), 120 },
{ OV(542), 115 },
{ OV(579), 110 },
{ OV(615), 105 },
{ OV(651), 100 },
{ OV(686), 95 },
{ OV(720), 90 },
{ OV(751), 85 },
{ OV(781), 80 },
{ OV(809), 75 },
{ OV(835), 70 },
{ OV(858), 65 },
{ OV(880), 60 },
{ OV(899), 55 },
{ OV(915), 50 },
{ OV(930), 45 },
{ OV(944), 40 },
{ OV(955), 35 },
{ OV(965), 30 }, // 78279.3
{ OV(974), 25 },
{ OV(981), 20 },
{ OV(988), 15 },
{ OV(993), 10 },
{ OV(998), 5 },
{ OV(1002), 0 },
};

View File

@@ -0,0 +1,62 @@
/**
* 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 <http://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
// 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 = {
{ OV( 1), 500 },
{ OV( 125), 300 }, // top rating 300C
{ OV( 142), 290 },
{ OV( 162), 280 },
{ OV( 185), 270 },
{ OV( 211), 260 },
{ OV( 240), 250 },
{ OV( 274), 240 },
{ OV( 312), 230 },
{ OV( 355), 220 },
{ OV( 401), 210 },
{ OV( 452), 200 },
{ OV( 506), 190 },
{ OV( 563), 180 },
{ OV( 620), 170 },
{ OV( 677), 160 },
{ OV( 732), 150 },
{ OV( 783), 140 },
{ OV( 830), 130 },
{ OV( 871), 120 },
{ OV( 906), 110 },
{ OV( 935), 100 },
{ OV( 958), 90 },
{ OV( 976), 80 },
{ OV( 990), 70 },
{ OV(1000), 60 },
{ OV(1008), 50 },
{ OV(1013), 40 },
{ OV(1017), 30 },
{ OV(1019), 20 },
{ OV(1021), 10 },
{ OV(1022), 0 }
};

View File

@@ -0,0 +1,62 @@
/**
* 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 <http://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
// 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 = {
{ OV( 1), 500 },
{ OV( 76), 300 },
{ OV( 87), 290 },
{ OV( 100), 280 },
{ OV( 114), 270 },
{ OV( 131), 260 },
{ OV( 152), 250 },
{ OV( 175), 240 },
{ OV( 202), 230 },
{ OV( 234), 220 },
{ OV( 271), 210 },
{ OV( 312), 200 },
{ OV( 359), 190 },
{ OV( 411), 180 },
{ OV( 467), 170 },
{ OV( 527), 160 },
{ OV( 590), 150 },
{ OV( 652), 140 },
{ OV( 713), 130 },
{ OV( 770), 120 },
{ OV( 822), 110 },
{ OV( 867), 100 },
{ OV( 905), 90 },
{ OV( 936), 80 },
{ OV( 961), 70 },
{ OV( 979), 60 },
{ OV( 993), 50 },
{ OV(1003), 40 },
{ OV(1010), 30 },
{ OV(1015), 20 },
{ OV(1018), 10 },
{ OV(1020), 0 }
};

View File

@@ -0,0 +1,64 @@
/**
* 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 <http://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 = {
{ OV( 1), 350 },
{ OV( 28), 250 }, // top rating 250C
{ OV( 31), 245 },
{ OV( 35), 240 },
{ OV( 39), 235 },
{ OV( 42), 230 },
{ OV( 44), 225 },
{ OV( 49), 220 },
{ OV( 53), 215 },
{ OV( 62), 210 },
{ OV( 71), 205 }, // fitted graphically
{ OV( 78), 200 }, // fitted graphically
{ OV( 94), 190 },
{ OV( 102), 185 },
{ OV( 116), 170 },
{ OV( 143), 160 },
{ OV( 183), 150 },
{ OV( 223), 140 },
{ OV( 270), 130 },
{ OV( 318), 120 },
{ OV( 383), 110 },
{ OV( 413), 105 },
{ OV( 439), 100 },
{ OV( 484), 95 },
{ OV( 513), 90 },
{ OV( 607), 80 },
{ OV( 664), 70 },
{ OV( 781), 60 },
{ OV( 810), 55 },
{ OV( 849), 50 },
{ OV( 914), 45 },
{ OV( 914), 40 },
{ OV( 935), 35 },
{ OV( 954), 30 },
{ OV( 970), 25 },
{ OV( 978), 22 },
{ OV(1008), 3 },
{ OV(1023), 0 } // to allow internal 0 degrees C
};

View File

@@ -0,0 +1,107 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 4.7 kOhm pull-up,
// Maker's Tool Works Kapton Bed Thermistor
// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3950
// r0: 100000
// t0: 25
// r1: 0 (parallel with rTherm)
// r2: 4700 (series with rTherm)
// beta: 3950
// min adc: 1 at 0.0048828125 V
// max adc: 1023 at 4.9951171875 V
const short temptable_60[][2] PROGMEM = {
{ OV( 51), 272 },
{ OV( 61), 258 },
{ OV( 71), 247 },
{ OV( 81), 237 },
{ OV( 91), 229 },
{ OV( 101), 221 },
{ OV( 131), 204 },
{ OV( 161), 190 },
{ OV( 191), 179 },
{ OV( 231), 167 },
{ OV( 271), 157 },
{ OV( 311), 148 },
{ OV( 351), 140 },
{ OV( 381), 135 },
{ OV( 411), 130 },
{ 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( 981), 23 },
{ OV( 991), 17 },
{ OV(1001), 9 },
{ OV(1008), 0 }
};

View File

@@ -0,0 +1,116 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 4.7 kOhm pull-up,
// Formbot / Vivedino high temp 100k thermistor
// 100KR13950181203
// Generated with modified version of https://www.thingiverse.com/thing:103668
// Using table 1 with datasheet values
// Resistance 100k Ohms at 25deg. C
// 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
{ OV( 12.07), 350 },
{ OV( 12.79), 345 },
{ OV( 13.59), 340 },
{ OV( 14.44), 335 },
{ OV( 15.37), 330 },
{ OV( 16.38), 325 },
{ OV( 17.46), 320 },
{ OV( 18.63), 315 },
{ OV( 19.91), 310 },
{ OV( 21.29), 305 },
{ OV( 22.79), 300 },
{ OV( 24.43), 295 },
{ OV( 26.21), 290 },
{ OV( 28.15), 285 },
{ OV( 30.27), 280 },
{ OV( 32.58), 275 },
{ OV( 35.10), 270 },
{ OV( 38.44), 265 },
{ OV( 40.89), 260 },
{ OV( 44.19), 255 },
{ OV( 47.83), 250 },
{ OV( 51.80), 245 },
{ OV( 56.20), 240 },
{ OV( 61.00), 235 },
{ OV( 66.30), 230 },
{ OV( 72.11), 225 },
{ OV( 78.51), 220 },
{ OV( 85.57), 215 },
{ OV( 93.34), 210 },
{ OV( 101.91), 205 },
{ OV( 111.34), 200 },
{ OV( 121.73), 195 },
{ OV( 133.17), 190 },
{ OV( 145.74), 185 },
{ OV( 159.57), 180 },
{ OV( 174.73), 175 },
{ OV( 191.35), 170 },
{ OV( 209.53), 165 },
{ OV( 229.35), 160 },
{ OV( 250.90), 155 },
{ OV( 274.25), 150 },
{ OV( 299.46), 145 },
{ OV( 326.52), 140 },
{ OV( 355.44), 135 },
{ OV( 386.15), 130 },
{ OV( 418.53), 125 },
{ OV( 452.43), 120 },
{ OV( 487.62), 115 },
{ OV( 523.82), 110 },
{ OV( 560.70), 105 },
{ OV( 597.88), 100 },
{ OV( 634.97), 95 },
{ OV( 671.55), 90 },
{ OV( 707.21), 85 },
{ OV( 741.54), 80 },
{ OV( 779.65), 75 },
{ OV( 809.57), 70 },
{ OV( 833.40), 65 },
{ OV( 859.55), 60 },
{ OV( 883.27), 55 },
{ OV( 904.53), 50 },
{ OV( 923.38), 45 },
{ OV( 939.91), 40 },
{ OV( 954.26), 35 },
{ OV( 966.59), 30 },
{ OV( 977.08), 25 },
{ OV( 985.92), 20 },
{ OV( 993.39), 15 },
{ OV( 999.42), 10 },
{ OV(1004.43), 5 },
{ OV(1008.51), 0 },
{ OV(1011.79), -5 },
{ OV(1014.40), -10 },
{ OV(1016.48), -15 },
{ OV(1018.10), -20 },
{ OV(1019.35), -25 },
{ OV(1020.32), -30 },
{ OV(1021.05), -35 },
{ OV(1021.60), -40 },
{ OV(1022.01), -45 },
{ OV(1022.31), -50 }
};

View File

@@ -0,0 +1,53 @@
/**
* 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 <http://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 = {
{ OV( 17.5), 850 },
{ OV( 17.9), 500 },
{ OV( 21.7), 480 },
{ OV( 26.6), 460 },
{ OV( 33.1), 440 },
{ OV( 41.0), 420 },
{ OV( 52.3), 400 },
{ OV( 67.7), 380 },
{ OV( 86.5), 360 },
{ OV( 112.0), 340 },
{ OV( 147.2), 320 },
{ OV( 194.0), 300 },
{ OV( 254.3), 280 },
{ OV( 330.2), 260 },
{ OV( 427.9), 240 },
{ OV( 533.4), 220 },
{ OV( 646.5), 200 },
{ OV( 754.4), 180 },
{ OV( 844.3), 160 },
{ OV( 911.7), 140 },
{ OV( 958.6), 120 },
{ OV( 988.8), 100 },
{ OV(1006.6), 80 },
{ OV(1015.8), 60 },
{ OV(1021.3), 30 },
{ OV( 1022), 25 },
{ OV( 1023), 20 }
};

View File

@@ -0,0 +1,99 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* This file was generated by tltgen on Thu Jul 5 15:46:43 2018.
* tltgen was created by Pieter Agten (pieter.agten@gmail.com).
*/
//#include "output_table.h"
/*
* Parameters:
* A: -0.000480634
* B: 0.00031362
* C: -2.03978e-07
*/
#define NUMTEMPS 61
const short temptable_666[NUMTEMPS][2] PROGMEM = {
{ OV( 1), 794 },
{ OV( 18), 288 },
{ OV( 35), 234 },
{ OV( 52), 207 },
{ OV( 69), 189 },
{ OV( 86), 176 },
{ OV(103), 166 },
{ OV(120), 157 },
{ OV(137) ,150 },
{ OV(154), 144 },
{ OV(172), 138 },
{ OV(189), 134 },
{ OV(206), 129 },
{ OV(223), 125 },
{ OV(240), 121 },
{ OV(257), 118 },
{ OV(274), 115 },
{ OV(291), 112 },
{ OV(308), 109 },
{ OV(325), 106 },
{ OV(342), 103 },
{ OV(359), 101 },
{ OV(376), 99 },
{ OV(393), 96 },
{ OV(410), 94 },
{ OV(427), 92 },
{ OV(444), 90 },
{ OV(461), 88 },
{ OV(478), 86 },
{ OV(495), 84 },
{ OV(512), 82 },
{ OV(530), 80 },
{ OV(547), 78 },
{ OV(564), 76 },
{ OV(581), 74 },
{ OV(598), 72 },
{ OV(615), 70 },
{ OV(632), 68 },
{ OV(649), 67 },
{ OV(666), 65 },
{ OV(683), 63 },
{ OV(700), 61 },
{ OV(717), 59 },
{ OV(734), 57 },
{ OV(751), 55 },
{ OV(768), 53 },
{ OV(785), 51 },
{ OV(802), 49 },
{ OV(819), 47 },
{ OV(836), 44 },
{ OV(853), 42 },
{ OV(871), 39 },
{ OV(888), 37 },
{ OV(905), 34 },
{ OV(922), 30 },
{ OV(939), 27 },
{ OV(956), 23 },
{ OV(973), 18 },
{ OV(990), 11 },
{ OV(1007), 2 },
{ OV(1023),-25 }
};

View File

@@ -0,0 +1,81 @@
/**
* 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 <http://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 = {
{ OV( 22 ), 500 },
{ OV( 23 ), 490 },
{ OV( 25 ), 480 },
{ OV( 27 ), 470 },
{ OV( 29 ), 460 },
{ OV( 32 ), 450 },
{ OV( 35 ), 440 },
{ OV( 38 ), 430 },
{ OV( 41 ), 420 },
{ OV( 45 ), 410 },
{ OV( 50 ), 400 },
{ OV( 55 ), 390 },
{ OV( 60 ), 380 },
{ OV( 67 ), 370 },
{ OV( 74 ), 360 },
{ OV( 82 ), 350 },
{ OV( 91 ), 340 },
{ OV( 102 ), 330 },
{ OV( 114 ), 320 },
{ OV( 127 ), 310 },
{ OV( 143 ), 300 },
{ OV( 161 ), 290 },
{ OV( 181 ), 280 },
{ OV( 204 ), 270 },
{ OV( 229 ), 260 },
{ OV( 259 ), 250 },
{ OV( 290 ), 240 },
{ OV( 325 ), 230 },
{ OV( 364 ), 220 },
{ OV( 407 ), 210 },
{ OV( 453 ), 200 },
{ OV( 501 ), 190 },
{ OV( 551 ), 180 },
{ OV( 603 ), 170 },
{ OV( 655 ), 160 },
{ OV( 706 ), 150 },
{ OV( 755 ), 140 },
{ OV( 801 ), 130 },
{ OV( 842 ), 120 },
{ OV( 879 ), 110 },
{ OV( 910 ), 100 },
{ OV( 936 ), 90 },
{ OV( 948 ), 85 },
{ OV( 958 ), 80 },
{ OV( 975 ), 70 },
{ OV( 988 ), 60 },
{ OV( 998 ), 50 },
{ OV(1006 ), 40 },
{ OV(1011 ), 30 },
{ OV(1013 ), 25 },
{ OV(1015 ), 20 },
{ OV(1018 ), 10 },
{ OV(1020 ), 0 },
{ OV(1021 ), -10 },
{ OV(1022 ), -20 }
};

View File

@@ -0,0 +1,84 @@
/**
* 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 <http://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 = {
{ OV( 1), 941 },
{ OV( 19), 362 },
{ OV( 37), 299 }, // top rating 300C
{ OV( 55), 266 },
{ OV( 73), 245 },
{ OV( 91), 229 },
{ OV( 109), 216 },
{ OV( 127), 206 },
{ OV( 145), 197 },
{ OV( 163), 190 },
{ OV( 181), 183 },
{ OV( 199), 177 },
{ OV( 217), 171 },
{ OV( 235), 166 },
{ OV( 253), 162 },
{ OV( 271), 157 },
{ OV( 289), 153 },
{ OV( 307), 149 },
{ OV( 325), 146 },
{ OV( 343), 142 },
{ OV( 361), 139 },
{ OV( 379), 135 },
{ OV( 397), 132 },
{ OV( 415), 129 },
{ OV( 433), 126 },
{ OV( 451), 123 },
{ OV( 469), 121 },
{ OV( 487), 118 },
{ OV( 505), 115 },
{ OV( 523), 112 },
{ OV( 541), 110 },
{ OV( 559), 107 },
{ OV( 577), 105 },
{ OV( 595), 102 },
{ OV( 613), 99 },
{ OV( 631), 97 },
{ OV( 649), 94 },
{ OV( 667), 92 },
{ OV( 685), 89 },
{ OV( 703), 86 },
{ OV( 721), 84 },
{ OV( 739), 81 },
{ OV( 757), 78 },
{ OV( 775), 75 },
{ OV( 793), 72 },
{ OV( 811), 69 },
{ OV( 829), 66 },
{ OV( 847), 62 },
{ OV( 865), 59 },
{ OV( 883), 55 },
{ OV( 901), 51 },
{ OV( 919), 46 },
{ OV( 937), 41 },
{ OV( 955), 35 },
{ OV( 973), 27 },
{ OV( 991), 17 },
{ OV(1009), 1 },
{ OV(1023), 0 } // to allow internal 0 degrees C
};

View File

@@ -0,0 +1,46 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// Stock BQ Hephestos 2 100k thermistor.
// Created on 29/12/2017 with an ambient temperature of 20C.
// 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 = {
{ OV( 18), 270 },
{ OV( 27), 248 },
{ OV( 34), 234 },
{ OV( 45), 220 },
{ OV( 61), 205 },
{ OV( 86), 188 },
{ OV( 123), 172 },
{ OV( 420), 110 },
{ OV( 590), 90 },
{ OV( 845), 56 },
{ OV( 970), 25 },
{ OV( 986), 20 },
{ OV( 994), 15 },
{ OV(1000), 10 },
{ OV(1005), 5 },
{ OV(1009), 0 } // safety
};

View File

@@ -0,0 +1,94 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3974 K, 4.7 kOhm pull-up, Honeywell 135-104LAF-J01
// R0 = 100000 Ohm
// T0 = 25 °C
// Beta = 3974
// R1 = 0 Ohm
// R2 = 4700 Ohm
const short temptable_71[][2] PROGMEM = {
{ OV( 35), 300 },
{ OV( 51), 269 },
{ OV( 59), 258 },
{ OV( 64), 252 },
{ OV( 71), 244 },
{ OV( 81), 235 },
{ OV( 87), 230 },
{ OV( 92), 226 },
{ OV( 102), 219 },
{ OV( 110), 214 },
{ OV( 115), 211 },
{ OV( 126), 205 },
{ OV( 128), 204 },
{ OV( 130), 203 },
{ OV( 132), 202 },
{ OV( 134), 201 },
{ OV( 136), 200 },
{ OV( 147), 195 },
{ OV( 154), 192 },
{ OV( 159), 190 },
{ OV( 164), 188 },
{ OV( 172), 185 },
{ OV( 175), 184 },
{ OV( 178), 183 },
{ OV( 181), 182 },
{ OV( 184), 181 },
{ OV( 187), 180 },
{ OV( 190), 179 },
{ OV( 193), 178 },
{ OV( 196), 177 },
{ OV( 199), 176 },
{ OV( 202), 175 },
{ OV( 205), 174 },
{ OV( 208), 173 },
{ OV( 215), 171 },
{ OV( 237), 165 },
{ OV( 256), 160 },
{ OV( 300), 150 },
{ OV( 351), 140 },
{ OV( 470), 120 },
{ OV( 504), 115 },
{ OV( 538), 110 },
{ OV( 745), 80 },
{ OV( 770), 76 },
{ OV( 806), 70 },
{ OV( 829), 66 },
{ OV( 860), 60 },
{ OV( 879), 56 },
{ OV( 888), 54 },
{ OV( 905), 50 },
{ OV( 924), 45 },
{ OV( 940), 40 },
{ OV( 955), 35 },
{ OV( 972), 28 },
{ OV( 974), 27 },
{ OV( 976), 26 },
{ OV( 978), 25 },
{ OV( 980), 24 },
{ OV( 987), 20 },
{ OV( 995), 15 },
{ OV(1001), 10 },
{ OV(1006), 5 },
{ OV(1010), 0 }
};

View File

@@ -0,0 +1,80 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* R25 = 100 kOhm, beta25 = 4100 K, 4.7 kOhm pull-up,
* Generic Silicon Heat Pad with NTC 100K thermistor
*
* Many generic silicone heat pads use the MGB18-104F39050L32 thermistor, applicable to various
* wattages and voltages. This table is correct if this part is used. It's been optimized
* to provide good granularity in the 60-110C range, good for PLA and ABS. For higher temperature
* filament (e.g., nylon) uncomment HIGH_TEMP_RANGE_75 for increased accuracy. If higher
* temperatures aren't used it can improve performance slightly to leave it commented out.
*/
//#define HIGH_TEMP_RANGE_75
const short temptable_75[][2] 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
{ OV(174.87), 175 }, // v=0.854 r=967.950 res=0.311 degC/count These values are valid. But they serve no
{ OV(191.64), 170 }, // v=0.936 r=1082.139 res=0.284 degC/count purpose. It is better to delete them so
{ OV(209.99), 165 }, // v=1.025 r=1212.472 res=0.260 degC/count the search is quicker and get to the meaningful
{ OV(230.02), 160 }, // v=1.123 r=1361.590 res=0.239 degC/count part of the table sooner.
{ OV(251.80), 155 }, // v=1.230 r=1532.621 res=0.220 degC/count
#endif
{ OV(275.43), 150 }, // v=1.345 r=1729.283 res=0.203 degC/count
#ifdef HIGH_TEMP_RANGE_75
{ OV(300.92), 145 }, // v=1.469 r=1956.004 res=0.189 degC/coun
#endif
{ OV( 328.32), 140 }, // v=1.603 r=2218.081 res=0.176 degC/count
{ OV( 388.65), 130 }, // v=1.898 r=2874.980 res=0.156 degC/count
{ OV( 421.39), 125 }, // v=2.058 r=3286.644 res=0.149 degC/count
{ OV( 455.65), 120 }, // v=2.225 r=3768.002 res=0.143 degC/count
{ OV( 491.17), 115 }, // v=2.398 r=4332.590 res=0.139 degC/count
{ OV( 527.68), 110 }, // v=2.577 r=4996.905 res=0.136 degC/count
{ OV( 564.81), 105 }, // v=2.758 r=5781.120 res=0.134 degC/count
{ OV( 602.19), 100 }, // v=2.940 r=6710.000 res=0.134 degC/count
{ OV( 676.03), 90 }, // v=3.301 r=9131.018 res=0.138 degC/count
{ OV( 745.85), 80 }, // v=3.642 r=12602.693 res=0.150 degC/count
{ OV( 778.31), 75 }, // v=3.800 r=14889.001 res=0.159 degC/count
{ OV( 808.75), 70 }, // v=3.949 r=17658.700 res=0.171 degC/count
{ OV( 836.94), 65 }, // v=4.087 r=21028.040 res=0.185 degC/count
{ OV( 862.74), 60 }, // v=4.213 r=25144.568 res=0.204 degC/count
{ OV( 886.08), 55 }, // v=4.327 r=30196.449 res=0.227 degC/count
{ OV( 906.97), 50 }, // v=4.429 r=36424.838 res=0.255 degC/count
{ OV( 941.65), 40 }, // v=4.598 r=53745.337 res=0.333 degC/count
{ OV( 967.76), 30 }, // v=4.725 r=80880.630 res=0.452 degC/count
{ OV( 978.03), 25 }, // v=4.776 r=100000.000 res=0.535 degC/count
{ OV( 981.68), 23 }, // v=4.793 r=109024.395 res=0.573 degC/count
{ OV( 983.41), 22 }, // v=4.802 r=113875.430 res=0.594 degC/count
{ OV( 985.08), 21 }, // v=4.810 r=118968.955 res=0.616 degC/count
{ OV( 986.70), 20 }, // v=4.818 r=124318.354 res=0.638 degC/count
{ OV( 993.94), 15 }, // v=4.853 r=155431.302 res=0.768 degC/count
{ OV( 999.96), 10 }, // v=4.883 r=195480.023 res=0.934 degC/count
{ OV(1008.95), 0 } // v=4.926 r=314997.575 res=1.418 degC/count
};

View File

@@ -0,0 +1,46 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// R25 = 100 kOhm, beta25 = 3950 K, 10 kOhm pull-up, NTCS0603E3104FHT
const short temptable_8[][2] PROGMEM = {
{ OV( 1), 704 },
{ OV( 54), 216 },
{ OV( 107), 175 },
{ OV( 160), 152 },
{ OV( 213), 137 },
{ OV( 266), 125 },
{ OV( 319), 115 },
{ OV( 372), 106 },
{ OV( 425), 99 },
{ OV( 478), 91 },
{ OV( 531), 85 },
{ OV( 584), 78 },
{ OV( 637), 71 },
{ OV( 690), 65 },
{ OV( 743), 58 },
{ OV( 796), 50 },
{ OV( 849), 42 },
{ OV( 902), 31 },
{ OV( 955), 17 },
{ OV(1008), 0 }
};

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 <http://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 = {
{ OV( 1), 936 },
{ OV( 36), 300 },
{ OV( 71), 246 },
{ OV( 106), 218 },
{ OV( 141), 199 },
{ OV( 176), 185 },
{ OV( 211), 173 },
{ OV( 246), 163 },
{ OV( 281), 155 },
{ OV( 316), 147 },
{ OV( 351), 140 },
{ OV( 386), 134 },
{ OV( 421), 128 },
{ OV( 456), 122 },
{ OV( 491), 117 },
{ OV( 526), 112 },
{ OV( 561), 107 },
{ OV( 596), 102 },
{ OV( 631), 97 },
{ OV( 666), 92 },
{ OV( 701), 87 },
{ OV( 736), 81 },
{ OV( 771), 76 },
{ OV( 806), 70 },
{ OV( 841), 63 },
{ OV( 876), 56 },
{ OV( 911), 48 },
{ OV( 946), 38 },
{ OV( 981), 23 },
{ OV(1005), 5 },
{ OV(1016), 0 }
};

View File

@@ -0,0 +1,64 @@
/**
* 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 <http://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 = {
{ 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
{ OV( 8.36), 320 }, // v=0.041 r= 82.336 res= 8.772 degC/count
{ OV( 9.51), 310 }, // v=0.046 r= 93.780 res= 7.535 degC/count
{ OV( 10.87), 300 }, // v=0.053 r= 107.281 res= 6.439 degC/count
{ OV( 12.47), 290 }, // v=0.061 r= 123.286 res= 5.473 degC/count
{ OV( 14.37), 280 }, // v=0.070 r= 142.360 res= 4.627 degC/count
{ OV( 16.64), 270 }, // v=0.081 r= 165.215 res= 3.891 degC/count
{ OV( 19.37), 260 }, // v=0.095 r= 192.758 res= 3.253 degC/count
{ OV( 22.65), 250 }, // v=0.111 r= 226.150 res= 2.705 degC/count
{ OV( 26.62), 240 }, // v=0.130 r= 266.891 res= 2.236 degC/count
{ OV( 31.46), 230 }, // v=0.154 r= 316.931 res= 1.839 degC/count
{ OV( 37.38), 220 }, // v=0.182 r= 378.822 res= 1.504 degC/count
{ OV( 44.65), 210 }, // v=0.218 r= 455.939 res= 1.224 degC/count
{ OV( 53.64), 200 }, // v=0.262 r= 552.778 res= 0.991 degC/count
{ OV( 64.78), 190 }, // v=0.316 r= 675.386 res= 0.799 degC/count
{ OV( 78.65), 180 }, // v=0.384 r= 831.973 res= 0.643 degC/count
{ OV( 95.94), 170 }, // v=0.468 r= 1033.801 res= 0.516 degC/count
{ OV(117.52), 160 }, // v=0.574 r= 1296.481 res= 0.414 degC/count
{ OV(144.42), 150 }, // v=0.705 r= 1641.900 res= 0.333 degC/count
{ OV(177.80), 140 }, // v=0.868 r= 2101.110 res= 0.269 degC/count
{ OV(218.89), 130 }, // v=1.069 r= 2718.725 res= 0.220 degC/count
{ OV(268.82), 120 }, // v=1.313 r= 3559.702 res= 0.183 degC/count
{ OV(328.35), 110 }, // v=1.603 r= 4719.968 res= 0.155 degC/count
{ OV(397.44), 100 }, // v=1.941 r= 6343.323 res= 0.136 degC/count
{ OV(474.90), 90 }, // v=2.319 r= 8648.807 res= 0.124 degC/count
{ OV(558.03), 80 }, // v=2.725 r= 11975.779 res= 0.118 degC/count
{ OV(642.76), 70 }, // v=3.138 r= 16859.622 res= 0.119 degC/count
{ OV(724.25), 60 }, // v=3.536 r= 24161.472 res= 0.128 degC/count
{ OV(797.93), 50 }, // v=3.896 r= 35295.361 res= 0.146 degC/count
{ OV(860.51), 40 }, // v=4.202 r= 52635.209 res= 0.178 degC/count
{ OV(910.55), 30 }, // v=4.446 r= 80262.251 res= 0.229 degC/count
{ OV(948.36), 20 }, // v=4.631 r=125374.433 res= 0.313 degC/count
{ OV(975.47), 10 }, // v=4.763 r=201020.458 res= 0.449 degC/count
{ OV(994.02), 0 } // v=4.854 r=331567.870 res= 0.676 degC/count
};

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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// User-defined table 1
// Dummy Thermistor table.. It will ALWAYS read a fixed value.
#ifndef DUMMY_THERMISTOR_998_VALUE
#define DUMMY_THERMISTOR_998_VALUE 25
#endif
const short temptable_998[][2] PROGMEM = {
{ OV( 1), DUMMY_THERMISTOR_998_VALUE },
{ OV(1023), DUMMY_THERMISTOR_998_VALUE }
};

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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
// User-defined table 2
// Dummy Thermistor table.. It will ALWAYS read a fixed value.
#ifndef DUMMY_THERMISTOR_999_VALUE
#define DUMMY_THERMISTOR_999_VALUE 25
#endif
const short temptable_999[][2] PROGMEM = {
{ OV( 1), DUMMY_THERMISTOR_999_VALUE },
{ OV(1023), DUMMY_THERMISTOR_999_VALUE }
};

View File

@@ -0,0 +1,394 @@
/**
* 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 <http://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))
#if ENABLED(HAL_ADC_FILTERED)
#define OVERSAMPLENR 1
#else
#define OVERSAMPLENR 16
#endif
#define MAX_RAW_THERMISTOR_VALUE (HAL_ADC_RANGE * (OVERSAMPLENR) - 1)
// Currently Marlin stores all oversampled ADC values as int16_t, make sure the HAL settings do not overflow 15bit
#if MAX_RAW_THERMISTOR_VALUE > ((1 << 15) - 1)
#error "MAX_RAW_THERMISTOR_VALUE is too large for int16_t. Reduce OVERSAMPLENR or HAL_ADC_RESOLUTION."
#endif
#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)
// Pt1000 and Pt100 handling
//
// Rt=R0*(1+a*T+b*T*T) [for T>0]
// a=3.9083E-3, b=-5.775E-7
#define PtA 3.9083E-3
#define PtB -5.775E-7
#define PtRt(T,R0) ((R0) * (1.0 + (PtA) * (T) + (PtB) * (T) * (T)))
#define PtAdVal(T,R0,Rup) (short)(1024 / (Rup / PtRt(T, R0) + 1))
#define PtLine(T,R0,Rup) { OV(PtAdVal(T, R0, Rup)), T }
#if ANY_THERMISTOR_IS(1) // beta25 = 4092 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "EPCOS"
#include "thermistor_1.h"
#endif
#if ANY_THERMISTOR_IS(2) // 4338 K, R25 = 200 kOhm, Pull-up = 4.7 kOhm, "ATC Semitec 204GT-2"
#include "thermistor_2.h"
#endif
#if ANY_THERMISTOR_IS(3) // beta25 = 4120 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Mendel-parts"
#include "thermistor_3.h"
#endif
#if ANY_THERMISTOR_IS(4) // beta25 = 3950 K, R25 = 10 kOhm, Pull-up = 4.7 kOhm, "Generic"
#include "thermistor_4.h"
#endif
#if ANY_THERMISTOR_IS(5) // beta25 = 4267 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "ParCan, ATC 104GT-2"
#include "thermistor_5.h"
#endif
#if ANY_THERMISTOR_IS(501) // 100K Zonestar thermistor
#include "thermistor_501.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
#if ANY_THERMISTOR_IS(6) // beta25 = 4092 K, R25 = 100 kOhm, Pull-up = 8.2 kOhm, "EPCOS ?"
#include "thermistor_6.h"
#endif
#if ANY_THERMISTOR_IS(7) // beta25 = 3974 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Honeywell 135-104LAG-J01"
#include "thermistor_7.h"
#endif
#if ANY_THERMISTOR_IS(71) // beta25 = 3974 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Honeywell 135-104LAF-J01"
#include "thermistor_71.h"
#endif
#if ANY_THERMISTOR_IS(8) // beta25 = 3950 K, R25 = 100 kOhm, Pull-up = 10 kOhm, "Vishay E3104FHT"
#include "thermistor_8.h"
#endif
#if ANY_THERMISTOR_IS(9) // beta25 = 3960 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "GE Sensing AL03006-58.2K-97-G1"
#include "thermistor_9.h"
#endif
#if ANY_THERMISTOR_IS(10) // beta25 = 3960 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "RS 198-961"
#include "thermistor_10.h"
#endif
#if ANY_THERMISTOR_IS(11) // beta25 = 3950 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "QU-BD silicone bed, QWG-104F-3950"
#include "thermistor_11.h"
#endif
#if ANY_THERMISTOR_IS(13) // beta25 = 4100 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Hisens"
#include "thermistor_13.h"
#endif
#if ANY_THERMISTOR_IS(15) // JGAurora A5 thermistor calibration
#include "thermistor_15.h"
#endif
#if ANY_THERMISTOR_IS(18) // ATC Semitec 204GT-2 (4.7k pullup) Dagoma.Fr - MKS_Base_DKU001327
#include "thermistor_18.h"
#endif
#if ANY_THERMISTOR_IS(20) // Pt100 with INA826 amp on Ultimaker v2.0 electronics
#include "thermistor_20.h"
#endif
#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(51) // beta25 = 4092 K, R25 = 100 kOhm, Pull-up = 1 kOhm, "EPCOS"
#include "thermistor_51.h"
#endif
#if ANY_THERMISTOR_IS(52) // beta25 = 4338 K, R25 = 200 kOhm, Pull-up = 1 kOhm, "ATC Semitec 204GT-2"
#include "thermistor_52.h"
#endif
#if ANY_THERMISTOR_IS(55) // beta25 = 4267 K, R25 = 100 kOhm, Pull-up = 1 kOhm, "ATC Semitec 104GT-2 (Used on ParCan)"
#include "thermistor_55.h"
#endif
#if ANY_THERMISTOR_IS(60) // beta25 = 3950 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Maker's Tool Works Kapton Bed"
#include "thermistor_60.h"
#endif
#if ANY_THERMISTOR_IS(61) // beta25 = 3950 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Formbot 350°C Thermistor"
#include "thermistor_61.h"
#endif
#if ANY_THERMISTOR_IS(66) // beta25 = 4500 K, R25 = 2.5 MOhm, Pull-up = 4.7 kOhm, "DyzeDesign 500 °C Thermistor"
#include "thermistor_66.h"
#endif
#if ANY_THERMISTOR_IS(67) // R25 = 500 KOhm, beta25 = 3800 K, 4.7 kOhm pull-up, SliceEngineering 450 °C Thermistor
#include "thermistor_67.h"
#endif
#if ANY_THERMISTOR_IS(12) // beta25 = 4700 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Personal calibration for Makibox hot bed"
#include "thermistor_12.h"
#endif
#if ANY_THERMISTOR_IS(70) // beta25 = 4100 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "Hephestos 2, bqh2 stock thermistor"
#include "thermistor_70.h"
#endif
#if ANY_THERMISTOR_IS(75) // beta25 = 4100 K, R25 = 100 kOhm, Pull-up = 4.7 kOhm, "MGB18-104F39050L32 thermistor"
#include "thermistor_75.h"
#endif
#if ANY_THERMISTOR_IS(99) // 100k bed thermistor with a 10K pull-up resistor (on some Wanhao i3 models)
#include "thermistor_99.h"
#endif
#if ANY_THERMISTOR_IS(110) // Pt100 with 1k0 pullup
#include "thermistor_110.h"
#endif
#if ANY_THERMISTOR_IS(147) // Pt100 with 4k7 pullup
#include "thermistor_147.h"
#endif
#if ANY_THERMISTOR_IS(201) // Pt100 with LMV324 Overlord
#include "thermistor_201.h"
#endif
#if ANY_THERMISTOR_IS(202) // 200K thermistor in Copymaker3D hotend
#include "thermistor_202.h"
#endif
#if ANY_THERMISTOR_IS(331) // Like table 1, but with 3V3 as input voltage for MEGA
#include "thermistor_331.h"
#endif
#if ANY_THERMISTOR_IS(332) // Like table 1, but with 3V3 as input voltage for DUE
#include "thermistor_332.h"
#endif
#if ANY_THERMISTOR_IS(666) // beta25 = UNK, R25 = 200K, Pull-up = 10 kOhm, "Unidentified 200K NTC thermistor (Einstart S)"
#include "thermistor_666.h"
#endif
#if ANY_THERMISTOR_IS(1010) // Pt1000 with 1k0 pullup
#include "thermistor_1010.h"
#endif
#if ANY_THERMISTOR_IS(1047) // Pt1000 with 4k7 pullup
#include "thermistor_1047.h"
#endif
#if ANY_THERMISTOR_IS(998) // User-defined table 1
#include "thermistor_998.h"
#endif
#if ANY_THERMISTOR_IS(999) // User-defined table 2
#include "thermistor_999.h"
#endif
#if ANY_THERMISTOR_IS(1000) // Custom
const short temptable_1000[][2] 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"
#else
#define HEATER_0_TEMPTABLE nullptr
#define HEATER_0_TEMPTABLE_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"
#else
#define HEATER_1_TEMPTABLE nullptr
#define HEATER_1_TEMPTABLE_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"
#else
#define HEATER_2_TEMPTABLE nullptr
#define HEATER_2_TEMPTABLE_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"
#else
#define HEATER_3_TEMPTABLE nullptr
#define HEATER_3_TEMPTABLE_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"
#else
#define HEATER_4_TEMPTABLE nullptr
#define HEATER_4_TEMPTABLE_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"
#else
#define HEATER_5_TEMPTABLE nullptr
#define HEATER_5_TEMPTABLE_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"
#else
#define HEATER_6_TEMPTABLE nullptr
#define HEATER_6_TEMPTABLE_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"
#else
#define HEATER_7_TEMPTABLE nullptr
#define HEATER_7_TEMPTABLE_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"
#else
#define BED_TEMPTABLE_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"
#else
#define CHAMBER_TEMPTABLE_LEN 0
#endif
#ifdef THERMISTORPROBE
#define PROBE_TEMPTABLE TT_NAME(THERMISTORPROBE)
#define PROBE_TEMPTABLE_LEN COUNT(PROBE_TEMPTABLE)
#else
#define PROBE_TEMPTABLE_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."
);
// 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
#else
#define HEATER_0_RAW_HI_TEMP 0
#define HEATER_0_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_1_RAW_HI_TEMP 0
#define HEATER_1_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_2_RAW_HI_TEMP 0
#define HEATER_2_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_3_RAW_HI_TEMP 0
#define HEATER_3_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_4_RAW_HI_TEMP 0
#define HEATER_4_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_5_RAW_HI_TEMP 0
#define HEATER_5_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#else
#define HEATER_6_RAW_HI_TEMP 0
#define HEATER_6_RAW_LO_TEMP MAX_RAW_THERMISTOR_VALUE
#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
#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
#endif
#endif
#undef REVERSE_TEMP_SENSOR_RANGE

1084
Marlin/src/module/tool_change.cpp Executable file

File diff suppressed because it is too large Load Diff

108
Marlin/src/module/tool_change.h Executable file
View File

@@ -0,0 +1,108 @@
/**
* 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 <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfigPre.h"
#include "../core/types.h"
#if EXTRUDERS > 1
typedef struct {
#if ENABLED(TOOLCHANGE_FILAMENT_SWAP)
float swap_length, extra_prime;
int16_t prime_speed, retract_speed;
#endif
#if ENABLED(TOOLCHANGE_PARK)
xy_pos_t change_point;
#endif
float z_raise;
} toolchange_settings_t;
extern toolchange_settings_t toolchange_settings;
#endif
#if DO_SWITCH_EXTRUDER
void move_extruder_servo(const uint8_t e);
#endif
#if ENABLED(SWITCHING_NOZZLE)
#if SWITCHING_NOZZLE_TWO_SERVOS
void lower_nozzle(const uint8_t e);
void raise_nozzle(const uint8_t e);
#else
void move_nozzle_servo(const uint8_t angle_index);
#endif
#endif
#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_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); }
void pe_solenoid_init();
#elif ENABLED(MAGNETIC_PARKING_EXTRUDER)
typedef struct MPESettings {
float parking_xpos[2], // M951 L R
grab_distance; // M951 I
feedRate_t slow_feedrate, // M951 J
fast_feedrate; // M951 H
float travel_distance, // M951 D
compensation_factor; // M951 C
} mpe_settings_t;
extern mpe_settings_t mpe_settings;
void mpe_settings_init();
#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();
#endif
#if ENABLED(SWITCHING_TOOLHEAD)
void swt_init();
#endif
/**
* Perform a tool-change, which may result in moving the
* previous tool out of the way and the new tool into place.
*/
void tool_change(const uint8_t tmp_extruder, bool no_move=false);