Move 'module' files
This commit is contained in:
1823
Marlin/src/module/configuration_store.cpp
Normal file
1823
Marlin/src/module/configuration_store.cpp
Normal file
File diff suppressed because it is too large
Load Diff
80
Marlin/src/module/configuration_store.h
Normal file
80
Marlin/src/module/configuration_store.h
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIGURATION_STORE_H
|
||||
#define CONFIGURATION_STORE_H
|
||||
|
||||
#include "MarlinConfig.h"
|
||||
|
||||
class MarlinSettings {
|
||||
public:
|
||||
MarlinSettings() { }
|
||||
|
||||
static void reset();
|
||||
static bool save();
|
||||
|
||||
#if ENABLED(EEPROM_SETTINGS)
|
||||
static bool load();
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
|
||||
// That can store is enabled
|
||||
FORCE_INLINE static int get_start_of_meshes() { return meshes_begin; }
|
||||
FORCE_INLINE static int get_end_of_meshes() { return meshes_end; }
|
||||
static int calc_num_meshes();
|
||||
static void store_mesh(int8_t slot);
|
||||
static void load_mesh(int8_t slot, void *into = 0);
|
||||
|
||||
//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; }
|
||||
#endif
|
||||
|
||||
#if DISABLED(DISABLE_M503)
|
||||
static void report(bool forReplay=false);
|
||||
#else
|
||||
FORCE_INLINE
|
||||
static void report(bool forReplay=false) { UNUSED(forReplay); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
static void postprocess();
|
||||
|
||||
#if ENABLED(EEPROM_SETTINGS)
|
||||
static bool eeprom_error;
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
|
||||
// That can store is enabled
|
||||
static int meshes_begin;
|
||||
const static int meshes_end = E2END - 128; // 128 is a placeholder for the size of the MAT; the MAT will always
|
||||
// live at the very end of the eeprom
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
extern MarlinSettings settings;
|
||||
|
||||
#endif // CONFIGURATION_STORE_H
|
451
Marlin/src/module/endstops.cpp
Normal file
451
Marlin/src/module/endstops.cpp
Normal file
@ -0,0 +1,451 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* endstops.cpp - A singleton object to manage endstops
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "cardreader.h"
|
||||
#include "endstops.h"
|
||||
#include "temperature.h"
|
||||
#include "stepper.h"
|
||||
#include "ultralcd.h"
|
||||
|
||||
// TEST_ENDSTOP: test the old and the current status of an endstop
|
||||
#define TEST_ENDSTOP(ENDSTOP) (TEST(current_endstop_bits & old_endstop_bits, ENDSTOP))
|
||||
|
||||
Endstops endstops;
|
||||
|
||||
// public:
|
||||
|
||||
bool Endstops::enabled, Endstops::enabled_globally; // Initialized by settings.load()
|
||||
volatile char Endstops::endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
uint16_t
|
||||
#else
|
||||
byte
|
||||
#endif
|
||||
Endstops::current_endstop_bits = 0,
|
||||
Endstops::old_endstop_bits = 0;
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
volatile bool Endstops::z_probe_enabled = false;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Class and Instance Methods
|
||||
*/
|
||||
|
||||
void Endstops::init() {
|
||||
|
||||
#if HAS_X_MIN
|
||||
#if ENABLED(ENDSTOPPULLUP_XMIN)
|
||||
SET_INPUT_PULLUP(X_MIN_PIN);
|
||||
#else
|
||||
SET_INPUT(X_MIN_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Y_MIN
|
||||
#if ENABLED(ENDSTOPPULLUP_YMIN)
|
||||
SET_INPUT_PULLUP(Y_MIN_PIN);
|
||||
#else
|
||||
SET_INPUT(Y_MIN_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Z_MIN
|
||||
#if ENABLED(ENDSTOPPULLUP_ZMIN)
|
||||
SET_INPUT_PULLUP(Z_MIN_PIN);
|
||||
#else
|
||||
SET_INPUT(Z_MIN_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Z2_MIN
|
||||
#if ENABLED(ENDSTOPPULLUP_ZMIN)
|
||||
SET_INPUT_PULLUP(Z2_MIN_PIN);
|
||||
#else
|
||||
SET_INPUT(Z2_MIN_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_X_MAX
|
||||
#if ENABLED(ENDSTOPPULLUP_XMAX)
|
||||
SET_INPUT_PULLUP(X_MAX_PIN);
|
||||
#else
|
||||
SET_INPUT(X_MAX_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Y_MAX
|
||||
#if ENABLED(ENDSTOPPULLUP_YMAX)
|
||||
SET_INPUT_PULLUP(Y_MAX_PIN);
|
||||
#else
|
||||
SET_INPUT(Y_MAX_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Z_MAX
|
||||
#if ENABLED(ENDSTOPPULLUP_ZMAX)
|
||||
SET_INPUT_PULLUP(Z_MAX_PIN);
|
||||
#else
|
||||
SET_INPUT(Z_MAX_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAS_Z2_MAX
|
||||
#if ENABLED(ENDSTOPPULLUP_ZMAX)
|
||||
SET_INPUT_PULLUP(Z2_MAX_PIN);
|
||||
#else
|
||||
SET_INPUT(Z2_MAX_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
|
||||
#if ENABLED(ENDSTOPPULLUP_ZMIN_PROBE)
|
||||
SET_INPUT_PULLUP(Z_MIN_PROBE_PIN);
|
||||
#else
|
||||
SET_INPUT(Z_MIN_PROBE_PIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // Endstops::init
|
||||
|
||||
void Endstops::report_state() {
|
||||
if (endstop_hit_bits) {
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
char chrX = ' ', chrY = ' ', chrZ = ' ', chrP = ' ';
|
||||
#define _SET_STOP_CHAR(A,C) (chr## A = C)
|
||||
#else
|
||||
#define _SET_STOP_CHAR(A,C) ;
|
||||
#endif
|
||||
|
||||
#define _ENDSTOP_HIT_ECHO(A,C) do{ \
|
||||
SERIAL_ECHOPAIR(" " STRINGIFY(A) ":", stepper.triggered_position_mm(A ##_AXIS)); \
|
||||
_SET_STOP_CHAR(A,C); }while(0)
|
||||
|
||||
#define _ENDSTOP_HIT_TEST(A,C) \
|
||||
if (TEST(endstop_hit_bits, A ##_MIN) || TEST(endstop_hit_bits, A ##_MAX)) \
|
||||
_ENDSTOP_HIT_ECHO(A,C)
|
||||
|
||||
#define ENDSTOP_HIT_TEST_X() _ENDSTOP_HIT_TEST(X,'X')
|
||||
#define ENDSTOP_HIT_TEST_Y() _ENDSTOP_HIT_TEST(Y,'Y')
|
||||
#define ENDSTOP_HIT_TEST_Z() _ENDSTOP_HIT_TEST(Z,'Z')
|
||||
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
|
||||
ENDSTOP_HIT_TEST_X();
|
||||
ENDSTOP_HIT_TEST_Y();
|
||||
ENDSTOP_HIT_TEST_Z();
|
||||
|
||||
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
|
||||
#define P_AXIS Z_AXIS
|
||||
if (TEST(endstop_hit_bits, Z_MIN_PROBE)) _ENDSTOP_HIT_ECHO(P, 'P');
|
||||
#endif
|
||||
SERIAL_EOL();
|
||||
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
lcd_status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP);
|
||||
#endif
|
||||
|
||||
hit_on_purpose();
|
||||
|
||||
#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT)
|
||||
if (stepper.abort_on_endstop_hit) {
|
||||
card.sdprinting = false;
|
||||
card.closefile();
|
||||
quickstop_stepper();
|
||||
thermalManager.disable_all_heaters(); // switch off all heaters.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // Endstops::report_state
|
||||
|
||||
void Endstops::M119() {
|
||||
SERIAL_PROTOCOLLNPGM(MSG_M119_REPORT);
|
||||
#if HAS_X_MIN
|
||||
SERIAL_PROTOCOLPGM(MSG_X_MIN);
|
||||
SERIAL_PROTOCOLLN(((READ(X_MIN_PIN)^X_MIN_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_X_MAX
|
||||
SERIAL_PROTOCOLPGM(MSG_X_MAX);
|
||||
SERIAL_PROTOCOLLN(((READ(X_MAX_PIN)^X_MAX_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Y_MIN
|
||||
SERIAL_PROTOCOLPGM(MSG_Y_MIN);
|
||||
SERIAL_PROTOCOLLN(((READ(Y_MIN_PIN)^Y_MIN_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Y_MAX
|
||||
SERIAL_PROTOCOLPGM(MSG_Y_MAX);
|
||||
SERIAL_PROTOCOLLN(((READ(Y_MAX_PIN)^Y_MAX_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Z_MIN
|
||||
SERIAL_PROTOCOLPGM(MSG_Z_MIN);
|
||||
SERIAL_PROTOCOLLN(((READ(Z_MIN_PIN)^Z_MIN_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Z2_MIN
|
||||
SERIAL_PROTOCOLPGM(MSG_Z2_MIN);
|
||||
SERIAL_PROTOCOLLN(((READ(Z2_MIN_PIN)^Z2_MIN_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Z_MAX
|
||||
SERIAL_PROTOCOLPGM(MSG_Z_MAX);
|
||||
SERIAL_PROTOCOLLN(((READ(Z_MAX_PIN)^Z_MAX_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if HAS_Z2_MAX
|
||||
SERIAL_PROTOCOLPGM(MSG_Z2_MAX);
|
||||
SERIAL_PROTOCOLLN(((READ(Z2_MAX_PIN)^Z2_MAX_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
|
||||
SERIAL_PROTOCOLPGM(MSG_Z_PROBE);
|
||||
SERIAL_PROTOCOLLN(((READ(Z_MIN_PROBE_PIN)^Z_MIN_PROBE_ENDSTOP_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
|
||||
SERIAL_PROTOCOLPGM(MSG_FILAMENT_RUNOUT_SENSOR);
|
||||
SERIAL_PROTOCOLLN(((READ(FIL_RUNOUT_PIN)^FIL_RUNOUT_INVERTING) ? MSG_ENDSTOP_HIT : MSG_ENDSTOP_OPEN));
|
||||
#endif
|
||||
} // Endstops::M119
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
|
||||
// Pass the result of the endstop test
|
||||
void Endstops::test_dual_z_endstops(const EndstopEnum es1, const EndstopEnum es2) {
|
||||
byte z_test = TEST_ENDSTOP(es1) | (TEST_ENDSTOP(es2) << 1); // bit 0 for Z, bit 1 for Z2
|
||||
if (z_test && stepper.current_block->steps[Z_AXIS] > 0) {
|
||||
SBI(endstop_hit_bits, Z_MIN);
|
||||
if (!stepper.performing_homing || (z_test == 0x3)) //if not performing home or if both endstops were trigged during homing...
|
||||
stepper.kill_current_block();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Check endstops - Called from ISR!
|
||||
void Endstops::update() {
|
||||
|
||||
#define _ENDSTOP(AXIS, MINMAX) AXIS ##_## MINMAX
|
||||
#define _ENDSTOP_PIN(AXIS, MINMAX) AXIS ##_## MINMAX ##_PIN
|
||||
#define _ENDSTOP_INVERTING(AXIS, MINMAX) AXIS ##_## MINMAX ##_ENDSTOP_INVERTING
|
||||
#define _ENDSTOP_HIT(AXIS, MINMAX) SBI(endstop_hit_bits, _ENDSTOP(AXIS, MINMAX))
|
||||
|
||||
// UPDATE_ENDSTOP_BIT: set the current endstop bits for an endstop to its status
|
||||
#define UPDATE_ENDSTOP_BIT(AXIS, MINMAX) SET_BIT(current_endstop_bits, _ENDSTOP(AXIS, MINMAX), (READ(_ENDSTOP_PIN(AXIS, MINMAX)) != _ENDSTOP_INVERTING(AXIS, MINMAX)))
|
||||
// COPY_BIT: copy the value of SRC_BIT to DST_BIT in DST
|
||||
#define COPY_BIT(DST, SRC_BIT, DST_BIT) SET_BIT(DST, DST_BIT, TEST(DST, SRC_BIT))
|
||||
|
||||
#define UPDATE_ENDSTOP(AXIS,MINMAX) do { \
|
||||
UPDATE_ENDSTOP_BIT(AXIS, MINMAX); \
|
||||
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX)) && stepper.current_block->steps[_AXIS(AXIS)] > 0) { \
|
||||
_ENDSTOP_HIT(AXIS, MINMAX); \
|
||||
stepper.endstop_triggered(_AXIS(AXIS)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
|
||||
// If G38 command is active check Z_MIN_PROBE for ALL movement
|
||||
if (G38_move) {
|
||||
UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
|
||||
if (TEST_ENDSTOP(_ENDSTOP(Z, MIN_PROBE))) {
|
||||
if (stepper.current_block->steps[_AXIS(X)] > 0) { _ENDSTOP_HIT(X, MIN); stepper.endstop_triggered(_AXIS(X)); }
|
||||
else if (stepper.current_block->steps[_AXIS(Y)] > 0) { _ENDSTOP_HIT(Y, MIN); stepper.endstop_triggered(_AXIS(Y)); }
|
||||
else if (stepper.current_block->steps[_AXIS(Z)] > 0) { _ENDSTOP_HIT(Z, MIN); stepper.endstop_triggered(_AXIS(Z)); }
|
||||
G38_endstop_hit = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Define conditions for checking endstops
|
||||
*/
|
||||
|
||||
#if IS_CORE
|
||||
#define S_(N) stepper.current_block->steps[CORE_AXIS_##N]
|
||||
#define D_(N) stepper.motor_direction(CORE_AXIS_##N)
|
||||
#endif
|
||||
|
||||
#if CORE_IS_XY || CORE_IS_XZ
|
||||
/**
|
||||
* Head direction in -X axis for CoreXY and CoreXZ bots.
|
||||
*
|
||||
* If steps differ, both axes are moving.
|
||||
* If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z, handled below)
|
||||
* If DeltaA == DeltaB, the movement is only in the 1st axis (X)
|
||||
*/
|
||||
#if ENABLED(COREXY) || ENABLED(COREXZ)
|
||||
#define X_CMP ==
|
||||
#else
|
||||
#define X_CMP !=
|
||||
#endif
|
||||
#define X_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) X_CMP D_(2)) )
|
||||
#define X_AXIS_HEAD X_HEAD
|
||||
#else
|
||||
#define X_MOVE_TEST stepper.current_block->steps[X_AXIS] > 0
|
||||
#define X_AXIS_HEAD X_AXIS
|
||||
#endif
|
||||
|
||||
#if CORE_IS_XY || CORE_IS_YZ
|
||||
/**
|
||||
* Head direction in -Y axis for CoreXY / CoreYZ bots.
|
||||
*
|
||||
* If steps differ, both axes are moving
|
||||
* If DeltaA == DeltaB, the movement is only in the 1st axis (X or Y)
|
||||
* If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z)
|
||||
*/
|
||||
#if ENABLED(COREYX) || ENABLED(COREYZ)
|
||||
#define Y_CMP ==
|
||||
#else
|
||||
#define Y_CMP !=
|
||||
#endif
|
||||
#define Y_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Y_CMP D_(2)) )
|
||||
#define Y_AXIS_HEAD Y_HEAD
|
||||
#else
|
||||
#define Y_MOVE_TEST stepper.current_block->steps[Y_AXIS] > 0
|
||||
#define Y_AXIS_HEAD Y_AXIS
|
||||
#endif
|
||||
|
||||
#if CORE_IS_XZ || CORE_IS_YZ
|
||||
/**
|
||||
* Head direction in -Z axis for CoreXZ or CoreYZ bots.
|
||||
*
|
||||
* If steps differ, both axes are moving
|
||||
* If DeltaA == DeltaB, the movement is only in the 1st axis (X or Y, already handled above)
|
||||
* If DeltaA == -DeltaB, the movement is only in the 2nd axis (Z)
|
||||
*/
|
||||
#if ENABLED(COREZX) || ENABLED(COREZY)
|
||||
#define Z_CMP ==
|
||||
#else
|
||||
#define Z_CMP !=
|
||||
#endif
|
||||
#define Z_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Z_CMP D_(2)) )
|
||||
#define Z_AXIS_HEAD Z_HEAD
|
||||
#else
|
||||
#define Z_MOVE_TEST stepper.current_block->steps[Z_AXIS] > 0
|
||||
#define Z_AXIS_HEAD Z_AXIS
|
||||
#endif
|
||||
|
||||
// With Dual X, endstops are only checked in the homing direction for the active extruder
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
#define E0_ACTIVE stepper.current_block->active_extruder == 0
|
||||
#define X_MIN_TEST ((X_HOME_DIR < 0 && E0_ACTIVE) || (X2_HOME_DIR < 0 && !E0_ACTIVE))
|
||||
#define X_MAX_TEST ((X_HOME_DIR > 0 && E0_ACTIVE) || (X2_HOME_DIR > 0 && !E0_ACTIVE))
|
||||
#else
|
||||
#define X_MIN_TEST true
|
||||
#define X_MAX_TEST true
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check and update endstops according to conditions
|
||||
*/
|
||||
|
||||
if (X_MOVE_TEST) {
|
||||
if (stepper.motor_direction(X_AXIS_HEAD)) {
|
||||
if (X_MIN_TEST) { // -direction
|
||||
#if HAS_X_MIN
|
||||
UPDATE_ENDSTOP(X, MIN);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (X_MAX_TEST) { // +direction
|
||||
#if HAS_X_MAX
|
||||
UPDATE_ENDSTOP(X, MAX);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (Y_MOVE_TEST) {
|
||||
if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
|
||||
#if HAS_Y_MIN
|
||||
UPDATE_ENDSTOP(Y, MIN);
|
||||
#endif
|
||||
}
|
||||
else { // +direction
|
||||
#if HAS_Y_MAX
|
||||
UPDATE_ENDSTOP(Y, MAX);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (Z_MOVE_TEST) {
|
||||
if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
|
||||
#if HAS_Z_MIN
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
|
||||
UPDATE_ENDSTOP_BIT(Z, MIN);
|
||||
#if HAS_Z2_MIN
|
||||
UPDATE_ENDSTOP_BIT(Z2, MIN);
|
||||
#else
|
||||
COPY_BIT(current_endstop_bits, Z_MIN, Z2_MIN);
|
||||
#endif
|
||||
|
||||
test_dual_z_endstops(Z_MIN, Z2_MIN);
|
||||
|
||||
#else // !Z_DUAL_ENDSTOPS
|
||||
|
||||
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
|
||||
if (z_probe_enabled) UPDATE_ENDSTOP(Z, MIN);
|
||||
#else
|
||||
UPDATE_ENDSTOP(Z, MIN);
|
||||
#endif
|
||||
|
||||
#endif // !Z_DUAL_ENDSTOPS
|
||||
|
||||
#endif // HAS_Z_MIN
|
||||
|
||||
// When closing the gap check the enabled probe
|
||||
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
|
||||
if (z_probe_enabled) {
|
||||
UPDATE_ENDSTOP(Z, MIN_PROBE);
|
||||
if (TEST_ENDSTOP(Z_MIN_PROBE)) SBI(endstop_hit_bits, Z_MIN_PROBE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else { // Z +direction. Gantry up, bed down.
|
||||
#if HAS_Z_MAX
|
||||
|
||||
// Check both Z dual endstops
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
|
||||
UPDATE_ENDSTOP_BIT(Z, MAX);
|
||||
#if HAS_Z2_MAX
|
||||
UPDATE_ENDSTOP_BIT(Z2, MAX);
|
||||
#else
|
||||
COPY_BIT(current_endstop_bits, Z_MAX, Z2_MAX);
|
||||
#endif
|
||||
|
||||
test_dual_z_endstops(Z_MAX, Z2_MAX);
|
||||
|
||||
// If this pin is not hijacked for the bed probe
|
||||
// then it belongs to the Z endstop
|
||||
#elif DISABLED(Z_MIN_PROBE_ENDSTOP) || Z_MAX_PIN != Z_MIN_PROBE_PIN
|
||||
|
||||
UPDATE_ENDSTOP(Z, MAX);
|
||||
|
||||
#endif // !Z_MIN_PROBE_PIN...
|
||||
#endif // Z_MAX_PIN
|
||||
}
|
||||
}
|
||||
|
||||
old_endstop_bits = current_endstop_bits;
|
||||
|
||||
} // Endstops::update()
|
102
Marlin/src/module/endstops.h
Normal file
102
Marlin/src/module/endstops.h
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* endstops.h - manages endstops
|
||||
*/
|
||||
|
||||
#ifndef ENDSTOPS_H
|
||||
#define ENDSTOPS_H
|
||||
|
||||
#include "enum.h"
|
||||
|
||||
class Endstops {
|
||||
|
||||
public:
|
||||
|
||||
static bool enabled, enabled_globally;
|
||||
static volatile char endstop_hit_bits; // use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT value
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static uint16_t
|
||||
#else
|
||||
static byte
|
||||
#endif
|
||||
current_endstop_bits, old_endstop_bits;
|
||||
|
||||
Endstops() {};
|
||||
|
||||
/**
|
||||
* Initialize the endstop pins
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Update the endstops bits from the pins
|
||||
*/
|
||||
static void update();
|
||||
|
||||
/**
|
||||
* Print an error message reporting the position when the endstops were last hit.
|
||||
*/
|
||||
static void report_state(); //call from somewhere to create an serial error message with the locations the endstops where hit, in case they were triggered
|
||||
|
||||
/**
|
||||
* Report endstop positions in response to M119
|
||||
*/
|
||||
static void M119();
|
||||
|
||||
// Enable / disable endstop checking globally
|
||||
static void enable_globally(bool onoff=true) { enabled_globally = enabled = onoff; }
|
||||
|
||||
// Enable / disable endstop checking
|
||||
static void enable(bool onoff=true) { enabled = onoff; }
|
||||
|
||||
// Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable
|
||||
static void not_homing() { enabled = enabled_globally; }
|
||||
|
||||
// Clear endstops (i.e., they were hit intentionally) to suppress the report
|
||||
static void hit_on_purpose() { endstop_hit_bits = 0; }
|
||||
|
||||
// Enable / disable endstop z-probe checking
|
||||
#if HAS_BED_PROBE
|
||||
static volatile bool z_probe_enabled;
|
||||
static void enable_z_probe(bool onoff=true) { z_probe_enabled = onoff; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static void test_dual_z_endstops(const EndstopEnum es1, const EndstopEnum es2);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern Endstops endstops;
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
#define ENDSTOPS_ENABLED (endstops.enabled || endstops.z_probe_enabled)
|
||||
#else
|
||||
#define ENDSTOPS_ENABLED endstops.enabled
|
||||
#endif
|
||||
|
||||
|
||||
#endif // ENDSTOPS_H
|
1559
Marlin/src/module/planner.cpp
Normal file
1559
Marlin/src/module/planner.cpp
Normal file
File diff suppressed because it is too large
Load Diff
478
Marlin/src/module/planner.h
Normal file
478
Marlin/src/module/planner.h
Normal file
@ -0,0 +1,478 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* planner.h
|
||||
*
|
||||
* Buffer movement commands and manage the acceleration profile plan
|
||||
*
|
||||
* Derived from Grbl
|
||||
* Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
*/
|
||||
|
||||
#ifndef PLANNER_H
|
||||
#define PLANNER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "enum.h"
|
||||
#include "Marlin.h"
|
||||
|
||||
#if HAS_ABL
|
||||
#include "vector_3.h"
|
||||
#endif
|
||||
|
||||
enum BlockFlagBit {
|
||||
// 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,
|
||||
|
||||
// Start from a halt at the start of this block, respecting the maximum allowed jerk.
|
||||
BLOCK_BIT_START_FROM_FULL_HALT,
|
||||
|
||||
// The block is busy
|
||||
BLOCK_BIT_BUSY
|
||||
};
|
||||
|
||||
enum BlockFlag {
|
||||
BLOCK_FLAG_RECALCULATE = _BV(BLOCK_BIT_RECALCULATE),
|
||||
BLOCK_FLAG_NOMINAL_LENGTH = _BV(BLOCK_BIT_NOMINAL_LENGTH),
|
||||
BLOCK_FLAG_START_FROM_FULL_HALT = _BV(BLOCK_BIT_START_FROM_FULL_HALT),
|
||||
BLOCK_FLAG_BUSY = _BV(BLOCK_BIT_BUSY)
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
uint8_t flag; // Block flags (See BlockFlag enum above)
|
||||
|
||||
unsigned char active_extruder; // The extruder to move (if E move)
|
||||
|
||||
// Fields used by the Bresenham algorithm for tracing the line
|
||||
int32_t steps[NUM_AXIS]; // Step count along each axis
|
||||
uint32_t step_event_count; // The number of step events required to complete this block
|
||||
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
|
||||
#endif
|
||||
|
||||
int32_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
|
||||
acceleration_rate; // The acceleration rate used for acceleration calculation
|
||||
|
||||
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;
|
||||
uint32_t abs_adv_steps_multiplier8; // Factorised by 2^8 to avoid float
|
||||
#elif ENABLED(ADVANCE)
|
||||
int32_t advance_rate;
|
||||
volatile int32_t initial_advance;
|
||||
volatile int32_t final_advance;
|
||||
float advance;
|
||||
#endif
|
||||
|
||||
// Fields used by the motion planner to manage acceleration
|
||||
float nominal_speed, // The nominal speed for this block in mm/sec
|
||||
entry_speed, // Entry speed at previous-current junction in mm/sec
|
||||
max_entry_speed, // Maximum allowable junction entry speed in mm/sec
|
||||
millimeters, // The total travel of this block in mm
|
||||
acceleration; // acceleration mm/sec^2
|
||||
|
||||
// Settings for the trapezoid generator
|
||||
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 FAN_COUNT > 0
|
||||
uint16_t fan_speed[FAN_COUNT];
|
||||
#endif
|
||||
|
||||
#if ENABLED(BARICUDA)
|
||||
uint8_t valve_pressure, e_to_p_pressure;
|
||||
#endif
|
||||
|
||||
uint32_t segment_time;
|
||||
|
||||
} block_t;
|
||||
|
||||
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
|
||||
|
||||
class Planner {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* A ring buffer of moves described in steps
|
||||
*/
|
||||
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_tail;
|
||||
|
||||
#if ENABLED(DISTINCT_E_FACTORS)
|
||||
static uint8_t last_extruder; // Respond to extruder change
|
||||
#endif
|
||||
|
||||
static float max_feedrate_mm_s[XYZE_N], // Max speeds in mm per second
|
||||
axis_steps_per_mm[XYZE_N],
|
||||
steps_to_mm[XYZE_N];
|
||||
static uint32_t max_acceleration_steps_per_s2[XYZE_N],
|
||||
max_acceleration_mm_per_s2[XYZE_N]; // Use M201 to override by software
|
||||
|
||||
static millis_t min_segment_time;
|
||||
static float min_feedrate_mm_s,
|
||||
acceleration, // Normal acceleration mm/s^2 DEFAULT ACCELERATION for all printing moves. M204 SXXXX
|
||||
retract_acceleration, // Retract acceleration mm/s^2 filament pull-back and push-forward while standing still in the other axes M204 TXXXX
|
||||
travel_acceleration, // Travel acceleration mm/s^2 DEFAULT ACCELERATION for all NON printing moves. M204 MXXXX
|
||||
max_jerk[XYZE], // The largest speed change requiring no acceleration
|
||||
min_travel_feedrate_mm_s;
|
||||
|
||||
#if HAS_ABL
|
||||
static bool abl_enabled; // Flag that bed leveling is enabled
|
||||
#if ABL_PLANAR
|
||||
static matrix_3x3 bed_level_matrix; // Transform to compensate for bed level
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
static float z_fade_height, inverse_z_fade_height;
|
||||
#endif
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
static float extruder_advance_k, advance_ed_ratio;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The current position of the tool in absolute steps
|
||||
* Recalculated if any axis_steps_per_mm are changed by gcode
|
||||
*/
|
||||
static long position[NUM_AXIS];
|
||||
|
||||
/**
|
||||
* Speed of previous path line segment
|
||||
*/
|
||||
static float previous_speed[NUM_AXIS];
|
||||
|
||||
/**
|
||||
* Nominal speed of previous path line segment
|
||||
*/
|
||||
static float previous_nominal_speed;
|
||||
|
||||
/**
|
||||
* Limit where 64bit math is necessary for acceleration calculation
|
||||
*/
|
||||
static uint32_t cutoff_long;
|
||||
|
||||
#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 long(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 long axis_segment_time[2][3];
|
||||
#endif
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
static float position_float[NUM_AXIS];
|
||||
#endif
|
||||
|
||||
#if ENABLED(ULTRA_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();
|
||||
|
||||
// Manage fans, paste pressure, etc.
|
||||
static void check_axes_activity();
|
||||
|
||||
/**
|
||||
* Number of moves currently in the planner
|
||||
*/
|
||||
static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail + BLOCK_BUFFER_SIZE); }
|
||||
|
||||
static bool is_full() { return (block_buffer_tail == BLOCK_MOD(block_buffer_head + 1)); }
|
||||
|
||||
#if PLANNER_LEVELING
|
||||
|
||||
#define ARG_X float lx
|
||||
#define ARG_Y float ly
|
||||
#define ARG_Z float lz
|
||||
|
||||
/**
|
||||
* Apply leveling to transform a cartesian position
|
||||
* as it will be given to the planner and steppers.
|
||||
*/
|
||||
static void apply_leveling(float &lx, float &ly, float &lz);
|
||||
static void apply_leveling(float logical[XYZ]) { apply_leveling(logical[X_AXIS], logical[Y_AXIS], logical[Z_AXIS]); }
|
||||
static void unapply_leveling(float logical[XYZ]);
|
||||
|
||||
#else
|
||||
|
||||
#define ARG_X const float &lx
|
||||
#define ARG_Y const float &ly
|
||||
#define ARG_Z const float &lz
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Planner::_buffer_line
|
||||
*
|
||||
* Add a new direct linear movement to the buffer.
|
||||
*
|
||||
* Leveling and kinematics should be applied ahead of this.
|
||||
*
|
||||
* a,b,c,e - target position in mm or degrees
|
||||
* fr_mm_s - (target) speed of the move (mm/s)
|
||||
* extruder - target extruder
|
||||
*/
|
||||
static void _buffer_line(const float &a, const float &b, const float &c, const float &e, float fr_mm_s, const uint8_t extruder);
|
||||
|
||||
static void _set_position_mm(const float &a, const float &b, const float &c, const float &e);
|
||||
|
||||
/**
|
||||
* Add a new linear movement to the buffer.
|
||||
* The target is NOT translated to delta/scara
|
||||
*
|
||||
* Leveling will be applied to input on cartesians.
|
||||
* Kinematic machines should call buffer_line_kinematic (for leveled moves).
|
||||
* (Cartesians may also call buffer_line_kinematic.)
|
||||
*
|
||||
* lx,ly,lz,e - target position in mm or degrees
|
||||
* fr_mm_s - (target) speed of the move (mm/s)
|
||||
* extruder - target extruder
|
||||
*/
|
||||
static FORCE_INLINE void buffer_line(ARG_X, ARG_Y, ARG_Z, const float &e, const float &fr_mm_s, const uint8_t extruder) {
|
||||
#if PLANNER_LEVELING && IS_CARTESIAN
|
||||
apply_leveling(lx, ly, lz);
|
||||
#endif
|
||||
_buffer_line(lx, ly, lz, e, fr_mm_s, extruder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new linear movement to the buffer.
|
||||
* The target is cartesian, it's translated to delta/scara if
|
||||
* needed.
|
||||
*
|
||||
* ltarget - x,y,z,e CARTESIAN target in mm
|
||||
* fr_mm_s - (target) speed of the move (mm/s)
|
||||
* extruder - target extruder
|
||||
*/
|
||||
static FORCE_INLINE void buffer_line_kinematic(const float ltarget[XYZE], const float &fr_mm_s, const uint8_t extruder) {
|
||||
#if PLANNER_LEVELING
|
||||
float lpos[XYZ] = { ltarget[X_AXIS], ltarget[Y_AXIS], ltarget[Z_AXIS] };
|
||||
apply_leveling(lpos);
|
||||
#else
|
||||
const float * const lpos = ltarget;
|
||||
#endif
|
||||
#if IS_KINEMATIC
|
||||
inverse_kinematics(lpos);
|
||||
_buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], ltarget[E_AXIS], fr_mm_s, extruder);
|
||||
#else
|
||||
_buffer_line(lpos[X_AXIS], lpos[Y_AXIS], lpos[Z_AXIS], ltarget[E_AXIS], fr_mm_s, extruder);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the planner.position and individual stepper positions.
|
||||
* Used by G92, G28, G29, and other procedures.
|
||||
*
|
||||
* 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 FORCE_INLINE void set_position_mm(ARG_X, ARG_Y, ARG_Z, const float &e) {
|
||||
#if PLANNER_LEVELING && IS_CARTESIAN
|
||||
apply_leveling(lx, ly, lz);
|
||||
#endif
|
||||
_set_position_mm(lx, ly, lz, e);
|
||||
}
|
||||
static void set_position_mm_kinematic(const float position[NUM_AXIS]);
|
||||
static void set_position_mm(const AxisEnum axis, const float &v);
|
||||
static FORCE_INLINE void set_z_position_mm(const float &z) { set_position_mm(Z_AXIS, z); }
|
||||
static FORCE_INLINE void set_e_position_mm(const float &e) { set_position_mm(AxisEnum(E_AXIS), e); }
|
||||
|
||||
/**
|
||||
* Sync from the stepper positions. (e.g., after an interrupted move)
|
||||
*/
|
||||
static void sync_from_steppers();
|
||||
|
||||
/**
|
||||
* Does the buffer have any blocks queued?
|
||||
*/
|
||||
static bool blocks_queued() { return (block_buffer_head != block_buffer_tail); }
|
||||
|
||||
/**
|
||||
* "Discards" the block and "releases" the memory.
|
||||
* Called when the current block is no longer needed.
|
||||
*/
|
||||
static void discard_current_block() {
|
||||
if (blocks_queued())
|
||||
block_buffer_tail = BLOCK_MOD(block_buffer_tail + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The current block. NULL if the buffer is empty.
|
||||
* This also marks the block as busy.
|
||||
*/
|
||||
static block_t* get_current_block() {
|
||||
if (blocks_queued()) {
|
||||
block_t* block = &block_buffer[block_buffer_tail];
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
block_buffer_runtime_us -= block->segment_time; //We can't be sure how long an active block will take, so don't count it.
|
||||
#endif
|
||||
SBI(block->flag, BLOCK_BIT_BUSY);
|
||||
return block;
|
||||
}
|
||||
else {
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
clear_block_buffer_runtime(); // paranoia. Buffer is empty now - so reset accumulated time to zero.
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLED(ULTRA_LCD)
|
||||
|
||||
static uint16_t block_buffer_runtime() {
|
||||
CRITICAL_SECTION_START
|
||||
millis_t bbru = block_buffer_runtime_us;
|
||||
CRITICAL_SECTION_END
|
||||
// To translate µs to ms a division by 1000 would be required.
|
||||
// We introduce 2.4% error here by dividing by 1024.
|
||||
// Doesn't matter because block_buffer_runtime_us is already too small an estimation.
|
||||
bbru >>= 10;
|
||||
// limit to about a minute.
|
||||
NOMORE(bbru, 0xFFFFul);
|
||||
return bbru;
|
||||
}
|
||||
|
||||
static void clear_block_buffer_runtime(){
|
||||
CRITICAL_SECTION_START
|
||||
block_buffer_runtime_us = 0;
|
||||
CRITICAL_SECTION_END
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Get the index of the next / previous block in the ring buffer
|
||||
*/
|
||||
static int8_t next_block_index(int8_t block_index) { return BLOCK_MOD(block_index + 1); }
|
||||
static int8_t prev_block_index(int8_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 -'acceleration') 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 at this point, in order
|
||||
* to reach 'target_velocity' using 'acceleration' within a given
|
||||
* 'distance'.
|
||||
*/
|
||||
static float max_allowable_speed(const float &accel, const float &target_velocity, const float &distance) {
|
||||
return SQRT(sq(target_velocity) - 2 * accel * distance);
|
||||
}
|
||||
|
||||
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 *next);
|
||||
static void forward_pass_kernel(const block_t *previous, block_t* const current);
|
||||
|
||||
static void reverse_pass();
|
||||
static void forward_pass();
|
||||
|
||||
static void recalculate_trapezoids();
|
||||
|
||||
static void recalculate();
|
||||
|
||||
};
|
||||
|
||||
#define PLANNER_XY_FEEDRATE() (min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]))
|
||||
|
||||
extern Planner planner;
|
||||
|
||||
#endif // PLANNER_H
|
194
Marlin/src/module/planner_bezier.cpp
Normal file
194
Marlin/src/module/planner_bezier.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* planner_bezier.cpp
|
||||
*
|
||||
* Compute and buffer movement commands for bezier curves
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
|
||||
#if ENABLED(BEZIER_CURVE_SUPPORT)
|
||||
|
||||
#include "planner.h"
|
||||
#include "language.h"
|
||||
#include "temperature.h"
|
||||
|
||||
// See the meaning in the documentation of cubic_b_spline().
|
||||
#define MIN_STEP 0.002
|
||||
#define MAX_STEP 0.1
|
||||
#define SIGMA 0.1
|
||||
|
||||
/* Compute the linear interpolation between to real numbers.
|
||||
*/
|
||||
inline static float interp(float a, float b, float t) { return (1.0 - 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).
|
||||
*/
|
||||
inline static float eval_bezier(float a, float b, float c, float d, float t) {
|
||||
float iab = interp(a, b, t);
|
||||
float ibc = interp(b, c, t);
|
||||
float icd = interp(c, d, t);
|
||||
float iabc = interp(iab, ibc, t);
|
||||
float ibcd = interp(ibc, icd, t);
|
||||
float iabcd = interp(iabc, ibcd, t);
|
||||
return iabcd;
|
||||
}
|
||||
|
||||
/**
|
||||
* We approximate Euclidean distance with the sum of the coordinates
|
||||
* offset (so-called "norm 1"), which is quicker to compute.
|
||||
*/
|
||||
inline static float dist1(float x1, float y1, float x2, float y2) { return FABS(x1 - x2) + FABS(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 float position[NUM_AXIS], const float target[NUM_AXIS], const float offset[4], float fr_mm_s, uint8_t extruder) {
|
||||
// Absolute first and second control points are recovered.
|
||||
float first0 = position[X_AXIS] + offset[0];
|
||||
float first1 = position[Y_AXIS] + offset[1];
|
||||
float second0 = target[X_AXIS] + offset[2];
|
||||
float second1 = target[Y_AXIS] + offset[3];
|
||||
float t = 0.0;
|
||||
|
||||
float bez_target[4];
|
||||
bez_target[X_AXIS] = position[X_AXIS];
|
||||
bez_target[Y_AXIS] = position[Y_AXIS];
|
||||
float step = MAX_STEP;
|
||||
|
||||
millis_t next_idle_ms = millis() + 200UL;
|
||||
|
||||
while (t < 1.0) {
|
||||
|
||||
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.0);
|
||||
float new_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], new_t);
|
||||
float new_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], new_t);
|
||||
for (;;) {
|
||||
if (new_t - t < (MIN_STEP)) break;
|
||||
float candidate_t = 0.5 * (t + new_t);
|
||||
float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t);
|
||||
float candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t);
|
||||
float interp_pos0 = 0.5 * (bez_target[X_AXIS] + new_pos0);
|
||||
float interp_pos1 = 0.5 * (bez_target[Y_AXIS] + 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;
|
||||
float candidate_t = t + 2.0 * (new_t - t);
|
||||
if (candidate_t >= 1.0) break;
|
||||
float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t);
|
||||
float candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t);
|
||||
float interp_pos0 = 0.5 * (bez_target[X_AXIS] + candidate_pos0);
|
||||
float interp_pos1 = 0.5 * (bez_target[Y_AXIS] + 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
|
||||
bez_target[X_AXIS] = new_pos0;
|
||||
bez_target[Y_AXIS] = new_pos1;
|
||||
// FIXME. The following two are wrong, since the parameter t is
|
||||
// not linear in the distance.
|
||||
bez_target[Z_AXIS] = interp(position[Z_AXIS], target[Z_AXIS], t);
|
||||
bez_target[E_AXIS] = interp(position[E_AXIS], target[E_AXIS], t);
|
||||
clamp_to_software_endstops(bez_target);
|
||||
planner.buffer_line_kinematic(bez_target, fr_mm_s, extruder);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BEZIER_CURVE_SUPPORT
|
43
Marlin/src/module/planner_bezier.h
Normal file
43
Marlin/src/module/planner_bezier.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* planner_bezier.h
|
||||
*
|
||||
* Compute and buffer movement commands for bezier curves
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLANNER_BEZIER_H
|
||||
#define PLANNER_BEZIER_H
|
||||
|
||||
#include "Marlin.h"
|
||||
|
||||
void cubic_b_spline(
|
||||
const float position[NUM_AXIS], // current position
|
||||
const float target[NUM_AXIS], // target position
|
||||
const float offset[4], // a pair of offsets
|
||||
float fr_mm_s,
|
||||
uint8_t extruder
|
||||
);
|
||||
|
||||
#endif // PLANNER_BEZIER_H
|
234
Marlin/src/module/printcounter.cpp
Normal file
234
Marlin/src/module/printcounter.cpp
Normal file
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Marlin.h"
|
||||
#include "printcounter.h"
|
||||
#include "duration_t.h"
|
||||
|
||||
PrintCounter::PrintCounter(): super() {
|
||||
this->loadStats();
|
||||
}
|
||||
|
||||
millis_t PrintCounter::deltaDuration() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("deltaDuration"));
|
||||
#endif
|
||||
|
||||
millis_t tmp = this->lastDuration;
|
||||
this->lastDuration = this->duration();
|
||||
return this->lastDuration - tmp;
|
||||
}
|
||||
|
||||
bool PrintCounter::isLoaded() {
|
||||
return this->loaded;
|
||||
}
|
||||
|
||||
void PrintCounter::incFilamentUsed(double const &amount) {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("incFilamentUsed"));
|
||||
#endif
|
||||
|
||||
// Refuses to update data if object is not loaded
|
||||
if (!this->isLoaded()) return;
|
||||
|
||||
this->data.filamentUsed += amount; // mm
|
||||
}
|
||||
|
||||
|
||||
void PrintCounter::initStats() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("initStats"));
|
||||
#endif
|
||||
|
||||
this->loaded = true;
|
||||
this->data = { 0, 0, 0, 0, 0.0 };
|
||||
|
||||
this->saveStats();
|
||||
eeprom_write_byte((uint8_t *) this->address, 0x16);
|
||||
}
|
||||
|
||||
void PrintCounter::loadStats() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("loadStats"));
|
||||
#endif
|
||||
|
||||
// Checks if the EEPROM block is initialized
|
||||
if (eeprom_read_byte((uint8_t *) this->address) != 0x16) this->initStats();
|
||||
else eeprom_read_block(&this->data,
|
||||
(void *)(this->address + sizeof(uint8_t)), sizeof(printStatistics));
|
||||
|
||||
this->loaded = true;
|
||||
}
|
||||
|
||||
void PrintCounter::saveStats() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("saveStats"));
|
||||
#endif
|
||||
|
||||
// Refuses to save data if object is not loaded
|
||||
if (!this->isLoaded()) return;
|
||||
|
||||
// Saves the struct to EEPROM
|
||||
eeprom_update_block(&this->data,
|
||||
(void *)(this->address + sizeof(uint8_t)), sizeof(printStatistics));
|
||||
}
|
||||
|
||||
void PrintCounter::showStats() {
|
||||
char buffer[21];
|
||||
duration_t elapsed;
|
||||
|
||||
SERIAL_PROTOCOLPGM(MSG_STATS);
|
||||
|
||||
SERIAL_ECHOPGM("Prints: ");
|
||||
SERIAL_ECHO(this->data.totalPrints);
|
||||
|
||||
SERIAL_ECHOPGM(", Finished: ");
|
||||
SERIAL_ECHO(this->data.finishedPrints);
|
||||
|
||||
SERIAL_ECHOPGM(", Failed: "); // Note: Removes 1 from failures with an active counter
|
||||
SERIAL_ECHO(this->data.totalPrints - this->data.finishedPrints
|
||||
- ((this->isRunning() || this->isPaused()) ? 1 : 0));
|
||||
|
||||
SERIAL_EOL();
|
||||
SERIAL_PROTOCOLPGM(MSG_STATS);
|
||||
|
||||
elapsed = this->data.printTime;
|
||||
elapsed.toString(buffer);
|
||||
|
||||
SERIAL_ECHOPGM("Total time: ");
|
||||
SERIAL_ECHO(buffer);
|
||||
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
SERIAL_ECHOPGM(" (");
|
||||
SERIAL_ECHO(this->data.printTime);
|
||||
SERIAL_CHAR(')');
|
||||
#endif
|
||||
|
||||
elapsed = this->data.longestPrint;
|
||||
elapsed.toString(buffer);
|
||||
|
||||
SERIAL_ECHOPGM(", Longest job: ");
|
||||
SERIAL_ECHO(buffer);
|
||||
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
SERIAL_ECHOPGM(" (");
|
||||
SERIAL_ECHO(this->data.longestPrint);
|
||||
SERIAL_CHAR(')');
|
||||
#endif
|
||||
|
||||
SERIAL_EOL();
|
||||
SERIAL_PROTOCOLPGM(MSG_STATS);
|
||||
|
||||
SERIAL_ECHOPGM("Filament used: ");
|
||||
SERIAL_ECHO(this->data.filamentUsed / 1000);
|
||||
SERIAL_ECHOPGM("m");
|
||||
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
void PrintCounter::tick() {
|
||||
if (!this->isRunning()) return;
|
||||
|
||||
static uint32_t update_last = millis(),
|
||||
eeprom_last = millis();
|
||||
|
||||
millis_t now = millis();
|
||||
|
||||
// Trying to get the amount of calculations down to the bare min
|
||||
const static uint16_t i = this->updateInterval * 1000;
|
||||
|
||||
if (now - update_last >= i) {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("tick"));
|
||||
#endif
|
||||
|
||||
this->data.printTime += this->deltaDuration();
|
||||
update_last = now;
|
||||
}
|
||||
|
||||
// Trying to get the amount of calculations down to the bare min
|
||||
const static millis_t j = this->saveInterval * 1000;
|
||||
if (now - eeprom_last >= j) {
|
||||
eeprom_last = now;
|
||||
this->saveStats();
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
bool PrintCounter::start() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("start"));
|
||||
#endif
|
||||
|
||||
bool paused = this->isPaused();
|
||||
|
||||
if (super::start()) {
|
||||
if (!paused) {
|
||||
this->data.totalPrints++;
|
||||
this->lastDuration = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
bool PrintCounter::stop() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("stop"));
|
||||
#endif
|
||||
|
||||
if (super::stop()) {
|
||||
this->data.finishedPrints++;
|
||||
this->data.printTime += this->deltaDuration();
|
||||
|
||||
if (this->duration() > this->data.longestPrint)
|
||||
this->data.longestPrint = this->duration();
|
||||
|
||||
this->saveStats();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
// @Override
|
||||
void PrintCounter::reset() {
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
PrintCounter::debug(PSTR("stop"));
|
||||
#endif
|
||||
|
||||
super::reset();
|
||||
this->lastDuration = 0;
|
||||
}
|
||||
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
|
||||
void PrintCounter::debug(const char func[]) {
|
||||
if (DEBUGGING(INFO)) {
|
||||
SERIAL_ECHOPGM("PrintCounter::");
|
||||
serialprintPGM(func);
|
||||
SERIAL_ECHOLNPGM("()");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
179
Marlin/src/module/printcounter.h
Normal file
179
Marlin/src/module/printcounter.h
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PRINTCOUNTER_H
|
||||
#define PRINTCOUNTER_H
|
||||
|
||||
#include "macros.h"
|
||||
#include "language.h"
|
||||
#include "stopwatch.h"
|
||||
|
||||
// Print debug messages with M111 S2
|
||||
//#define DEBUG_PRINTCOUNTER
|
||||
|
||||
struct printStatistics { // 16 bytes (20 with real doubles)
|
||||
//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
|
||||
double filamentUsed; // Accumulated filament consumed in mm
|
||||
};
|
||||
|
||||
class PrintCounter: public Stopwatch {
|
||||
private:
|
||||
typedef Stopwatch super;
|
||||
|
||||
printStatistics data;
|
||||
|
||||
/**
|
||||
* @brief EEPROM address
|
||||
* @details Defines the start offset address where the data is stored.
|
||||
*/
|
||||
#if ENABLED(I2C_EEPROM) || ENABLED(SPI_EEPROM)
|
||||
// round up address to next page boundary (assuming 32 byte pages)
|
||||
const uint32_t address = 0x40;
|
||||
#elif defined(CPU_32_BIT)
|
||||
const uint32_t address = 0x32;
|
||||
#else
|
||||
const uint16_t address = 0x32;
|
||||
#endif
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
const 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).
|
||||
*/
|
||||
const uint16_t saveInterval = 3600;
|
||||
|
||||
/**
|
||||
* @brief Timestamp of the last call to deltaDuration()
|
||||
* @details Stores the timestamp of the last deltaDuration(), this is
|
||||
* required due to the updateInterval cycle.
|
||||
*/
|
||||
millis_t lastDuration;
|
||||
|
||||
/**
|
||||
* @brief Stats were loaded from EERPROM
|
||||
* @details If set to true it indicates if the statistical data was already
|
||||
* loaded from the EEPROM.
|
||||
*/
|
||||
bool loaded = false;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief dT since the last call
|
||||
* @details Returns 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.
|
||||
*/
|
||||
millis_t deltaDuration();
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Class constructor
|
||||
*/
|
||||
PrintCounter();
|
||||
|
||||
/**
|
||||
* @brief Checks if Print Statistics has been loaded
|
||||
* @details Returns true if the statistical data has been loaded.
|
||||
* @return bool
|
||||
*/
|
||||
bool isLoaded();
|
||||
|
||||
/**
|
||||
* @brief Increments the total filament used
|
||||
* @details The total filament used counter will be incremented by "amount".
|
||||
*
|
||||
* @param amount The amount of filament used in mm
|
||||
*/
|
||||
void incFilamentUsed(double const &amount);
|
||||
|
||||
/**
|
||||
* @brief Resets the Print Statistics
|
||||
* @details Resets the statistics to zero and saves them to EEPROM creating
|
||||
* also the magic header.
|
||||
*/
|
||||
void initStats();
|
||||
|
||||
/**
|
||||
* @brief Loads the Print Statistics
|
||||
* @details Loads the statistics from EEPROM
|
||||
*/
|
||||
void loadStats();
|
||||
|
||||
/**
|
||||
* @brief Saves the Print Statistics
|
||||
* @details Saves the statistics to EEPROM
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void showStats();
|
||||
|
||||
/**
|
||||
* @brief Return the currently loaded statistics
|
||||
* @details Return the raw data, in the same structure used internally
|
||||
*/
|
||||
printStatistics getStats() { return this->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.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
/**
|
||||
* The following functions are being overridden
|
||||
*/
|
||||
bool start();
|
||||
bool stop();
|
||||
void reset();
|
||||
|
||||
#if ENABLED(DEBUG_PRINTCOUNTER)
|
||||
|
||||
/**
|
||||
* @brief Prints a debug message
|
||||
* @details Prints a simple debug message "PrintCounter::function"
|
||||
*/
|
||||
static void debug(const char func[]);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // PRINTCOUNTER_H
|
174
Marlin/src/module/speed_lookuptable.h
Normal file
174
Marlin/src/module/speed_lookuptable.h
Normal file
@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SPEED_LOOKUPTABLE_H
|
||||
#define SPEED_LOOKUPTABLE_H
|
||||
|
||||
#include "Marlin.h"
|
||||
|
||||
#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
|
||||
|
||||
#endif // SPEED_LOOKUPTABLE_H
|
1701
Marlin/src/module/stepper.cpp
Normal file
1701
Marlin/src/module/stepper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
401
Marlin/src/module/stepper.h
Normal file
401
Marlin/src/module/stepper.h
Normal file
@ -0,0 +1,401 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef STEPPER_H
|
||||
#define STEPPER_H
|
||||
|
||||
#include "planner.h"
|
||||
#include "speed_lookuptable.h"
|
||||
#include "stepper_indirection.h"
|
||||
#include "language.h"
|
||||
#include "types.h"
|
||||
|
||||
class Stepper;
|
||||
extern Stepper stepper;
|
||||
|
||||
class Stepper {
|
||||
|
||||
public:
|
||||
|
||||
static block_t* current_block; // A pointer to the block currently being traced
|
||||
|
||||
#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
|
||||
static bool abort_on_endstop_hit;
|
||||
#endif
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static bool performing_homing;
|
||||
#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];
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
static uint8_t last_direction_bits; // The next stepping-bits to be output
|
||||
static uint16_t cleaning_buffer_counter;
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static bool locked_z_motor, locked_z2_motor;
|
||||
#endif
|
||||
|
||||
// Counter variables for the Bresenham line tracer
|
||||
static long counter_X, counter_Y, counter_Z, counter_E;
|
||||
static volatile uint32_t step_events_completed; // The number of step events executed in the current block
|
||||
|
||||
#if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
|
||||
static HAL_TIMER_TYPE nextMainISR, nextAdvanceISR, eISR_Rate;
|
||||
#define _NEXT_ISR(T) nextMainISR = T
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
static volatile int e_steps[E_STEPPERS];
|
||||
static int final_estep_rate;
|
||||
static int current_estep_rate[E_STEPPERS]; // Actual extruder speed [steps/s]
|
||||
static int current_adv_steps[E_STEPPERS]; // The amount of current added esteps due to advance.
|
||||
// i.e., the current amount of pressure applied
|
||||
// to the spring (=filament).
|
||||
#else
|
||||
static long e_steps[E_STEPPERS];
|
||||
static long advance_rate, advance, final_advance;
|
||||
static long old_advance;
|
||||
#endif
|
||||
#else
|
||||
#define _NEXT_ISR(T) HAL_timer_set_count(STEP_TIMER_NUM, T);
|
||||
#endif // ADVANCE or LIN_ADVANCE
|
||||
|
||||
static long acceleration_time, deceleration_time;
|
||||
//unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
|
||||
static HAL_TIMER_TYPE acc_step_rate; // needed for deceleration start point
|
||||
static uint8_t step_loops, step_loops_nominal;
|
||||
static HAL_TIMER_TYPE OCR1A_nominal;
|
||||
|
||||
static volatile long endstops_trigsteps[XYZ];
|
||||
static volatile long endstops_stepsTotal, endstops_stepsDone;
|
||||
|
||||
//
|
||||
// Positions of stepper motors, in step units
|
||||
//
|
||||
static volatile long count_position[NUM_AXIS];
|
||||
|
||||
//
|
||||
// Current direction of stepper motors (+1 or -1)
|
||||
//
|
||||
static volatile signed char count_direction[NUM_AXIS];
|
||||
|
||||
//
|
||||
// Mixing extruder mix counters
|
||||
//
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
static long counter_m[MIXING_STEPPERS];
|
||||
#define MIXING_STEPPERS_LOOP(VAR) \
|
||||
for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++) \
|
||||
if (current_block->mix_event_count[VAR])
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Constructor / initializer
|
||||
//
|
||||
Stepper() { };
|
||||
|
||||
//
|
||||
// Initialize stepper hardware
|
||||
//
|
||||
static void init();
|
||||
|
||||
//
|
||||
// Interrupt Service Routines
|
||||
//
|
||||
|
||||
static void isr();
|
||||
|
||||
#if ENABLED(ADVANCE) || ENABLED(LIN_ADVANCE)
|
||||
static void advance_isr();
|
||||
static void advance_isr_scheduler();
|
||||
#endif
|
||||
|
||||
//
|
||||
// Block until all buffered steps are executed
|
||||
//
|
||||
static void synchronize();
|
||||
|
||||
//
|
||||
// Set the current position in steps
|
||||
//
|
||||
static void set_position(const long &a, const long &b, const long &c, const long &e);
|
||||
static void set_position(const AxisEnum &a, const long &v);
|
||||
static void set_e_position(const long &e);
|
||||
|
||||
//
|
||||
// Set direction bits for all steppers
|
||||
//
|
||||
static void set_directions();
|
||||
|
||||
//
|
||||
// Get the position of a stepper, in steps
|
||||
//
|
||||
static long position(AxisEnum axis);
|
||||
|
||||
//
|
||||
// Report the positions of the steppers, in steps
|
||||
//
|
||||
static void report_positions();
|
||||
|
||||
//
|
||||
// Get the position (mm) of an axis based on stepper position(s)
|
||||
//
|
||||
static float get_axis_position_mm(AxisEnum axis);
|
||||
|
||||
//
|
||||
// SCARA AB axes are in degrees, not mm
|
||||
//
|
||||
#if IS_SCARA
|
||||
static FORCE_INLINE float get_axis_position_degrees(AxisEnum axis) { return get_axis_position_mm(axis); }
|
||||
#endif
|
||||
|
||||
//
|
||||
// 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 void wake_up();
|
||||
|
||||
//
|
||||
// Wait for moves to finish and disable all steppers
|
||||
//
|
||||
static void finish_and_disable();
|
||||
|
||||
//
|
||||
// Quickly stop all steppers and clear the blocks queue
|
||||
//
|
||||
static void quick_stop();
|
||||
|
||||
//
|
||||
// The direction of a single motor
|
||||
//
|
||||
static FORCE_INLINE bool motor_direction(AxisEnum axis) { return TEST(last_direction_bits, 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);
|
||||
static void microstep_mode(const uint8_t driver, const uint8_t stepping);
|
||||
static void microstep_readings();
|
||||
#endif
|
||||
|
||||
#if ENABLED(Z_DUAL_ENDSTOPS)
|
||||
static FORCE_INLINE void set_homing_flag(const bool state) { performing_homing = state; }
|
||||
static FORCE_INLINE void set_z_lock(const bool state) { locked_z_motor = state; }
|
||||
static FORCE_INLINE void set_z2_lock(const bool state) { locked_z2_motor = state; }
|
||||
#endif
|
||||
|
||||
#if ENABLED(BABYSTEPPING)
|
||||
static void babystep(const AxisEnum axis, const bool direction); // perform a short step with a single stepper motor, outside of any convention
|
||||
#endif
|
||||
|
||||
static inline void kill_current_block() {
|
||||
step_events_completed = current_block->step_event_count;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle a triggered endstop
|
||||
//
|
||||
static void endstop_triggered(AxisEnum axis);
|
||||
|
||||
//
|
||||
// Triggered position of an axis in mm (not core-savvy)
|
||||
//
|
||||
static FORCE_INLINE float triggered_position_mm(AxisEnum axis) {
|
||||
return endstops_trigsteps[axis] * planner.steps_to_mm[axis];
|
||||
}
|
||||
|
||||
#if HAS_MOTOR_CURRENT_PWM
|
||||
static void refresh_motor_power();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
static FORCE_INLINE HAL_TIMER_TYPE calc_timer(HAL_TIMER_TYPE step_rate) {
|
||||
HAL_TIMER_TYPE timer;
|
||||
|
||||
NOMORE(step_rate, MAX_STEP_FREQUENCY);
|
||||
|
||||
// TODO: HAL: tidy this up, use condtionals_post.h
|
||||
#ifdef CPU_32_BIT
|
||||
#if ENABLED(DISABLE_MULTI_STEPPING)
|
||||
step_loops = 1;
|
||||
#else
|
||||
if (step_rate > STEP_DOUBLER_FREQUENCY * 2) { // If steprate > (STEP_DOUBLER_FREQUENCY * 2) kHz >> step 4 times
|
||||
step_rate >>= 2;
|
||||
step_loops = 4;
|
||||
}
|
||||
else if (step_rate > STEP_DOUBLER_FREQUENCY) { // If steprate > STEP_DOUBLER_FREQUENCY kHz >> step 2 times
|
||||
step_rate >>= 1;
|
||||
step_loops = 2;
|
||||
}
|
||||
else {
|
||||
step_loops = 1;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (step_rate > 20000) { // If steprate > 20kHz >> step 4 times
|
||||
step_rate >>= 2;
|
||||
step_loops = 4;
|
||||
}
|
||||
else if (step_rate > 10000) { // If steprate > 10kHz >> step 2 times
|
||||
step_rate >>= 1;
|
||||
step_loops = 2;
|
||||
}
|
||||
else {
|
||||
step_loops = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPU_32_BIT
|
||||
// In case of high-performance processor, it is able to calculate in real-time
|
||||
timer = (uint32_t)(HAL_STEPPER_TIMER_RATE) / step_rate;
|
||||
if (timer < (HAL_STEPPER_TIMER_RATE / (STEP_DOUBLER_FREQUENCY * 2))) { // (STEP_DOUBLER_FREQUENCY * 2 kHz - this should never happen)
|
||||
timer = (HAL_STEPPER_TIMER_RATE / (STEP_DOUBLER_FREQUENCY * 2));
|
||||
}
|
||||
#else
|
||||
NOLESS(step_rate, F_CPU / 500000);
|
||||
step_rate -= F_CPU / 500000; // Correct for minimal speed
|
||||
if (step_rate >= (8 * 256)) { // higher step rate
|
||||
unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate >> 8)][0];
|
||||
unsigned char tmp_step_rate = (step_rate & 0x00ff);
|
||||
unsigned short gain = (unsigned short)pgm_read_word_near(table_address + 2);
|
||||
MultiU16X8toH16(timer, tmp_step_rate, gain);
|
||||
timer = (unsigned short)pgm_read_word_near(table_address) - timer;
|
||||
}
|
||||
else { // lower step rates
|
||||
unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
|
||||
table_address += ((step_rate) >> 1) & 0xfffc;
|
||||
timer = (unsigned short)pgm_read_word_near(table_address);
|
||||
timer -= (((unsigned short)pgm_read_word_near(table_address + 2) * (unsigned char)(step_rate & 0x0007)) >> 3);
|
||||
}
|
||||
if (timer < 100) { // (20kHz - this should never happen)
|
||||
timer = 100;
|
||||
MYSERIAL.print(MSG_STEPPER_TOO_HIGH);
|
||||
MYSERIAL.println(step_rate);
|
||||
}
|
||||
#endif
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
// Initialize the trapezoid generator from the current block.
|
||||
// Called whenever a new block begins.
|
||||
static FORCE_INLINE void trapezoid_generator_reset() {
|
||||
|
||||
static int8_t last_extruder = -1;
|
||||
|
||||
if (current_block->direction_bits != last_direction_bits || current_block->active_extruder != last_extruder) {
|
||||
last_direction_bits = current_block->direction_bits;
|
||||
last_extruder = current_block->active_extruder;
|
||||
set_directions();
|
||||
}
|
||||
|
||||
#if ENABLED(ADVANCE)
|
||||
|
||||
advance = current_block->initial_advance;
|
||||
final_advance = current_block->final_advance;
|
||||
|
||||
// Do E steps + advance steps
|
||||
#if ENABLED(MIXING_EXTRUDER)
|
||||
long advance_factor = (advance >> 8) - old_advance;
|
||||
// ...for mixing steppers proportionally
|
||||
MIXING_STEPPERS_LOOP(j)
|
||||
e_steps[j] += advance_factor * current_block->step_event_count / current_block->mix_event_count[j];
|
||||
#else
|
||||
// ...for the active extruder
|
||||
e_steps[TOOL_E_INDEX] += ((advance >> 8) - old_advance);
|
||||
#endif
|
||||
|
||||
old_advance = advance >> 8;
|
||||
|
||||
#endif
|
||||
|
||||
deceleration_time = 0;
|
||||
// step_rate to timer interval
|
||||
OCR1A_nominal = calc_timer(current_block->nominal_rate);
|
||||
// make a note of the number of step loops required at nominal speed
|
||||
step_loops_nominal = step_loops;
|
||||
acc_step_rate = current_block->initial_rate;
|
||||
acceleration_time = calc_timer(acc_step_rate);
|
||||
_NEXT_ISR(acceleration_time);
|
||||
|
||||
#if ENABLED(LIN_ADVANCE)
|
||||
if (current_block->use_advance_lead) {
|
||||
current_estep_rate[current_block->active_extruder] = ((unsigned long)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;
|
||||
final_estep_rate = (current_block->nominal_rate * current_block->abs_adv_steps_multiplier8) >> 17;
|
||||
}
|
||||
#endif
|
||||
|
||||
// SERIAL_ECHO_START();
|
||||
// SERIAL_ECHOPGM("advance :");
|
||||
// SERIAL_ECHO(current_block->advance/256.0);
|
||||
// SERIAL_ECHOPGM("advance rate :");
|
||||
// SERIAL_ECHO(current_block->advance_rate/256.0);
|
||||
// SERIAL_ECHOPGM("initial advance :");
|
||||
// SERIAL_ECHO(current_block->initial_advance/256.0);
|
||||
// SERIAL_ECHOPGM("final advance :");
|
||||
// SERIAL_ECHOLN(current_block->final_advance/256.0);
|
||||
}
|
||||
|
||||
#if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM
|
||||
static void digipot_init();
|
||||
#endif
|
||||
|
||||
#if HAS_MICROSTEPS
|
||||
static void microstep_init();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // STEPPER_H
|
338
Marlin/src/module/stepper_indirection.cpp
Normal file
338
Marlin/src/module/stepper_indirection.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* stepper_indirection.cpp
|
||||
*
|
||||
* Stepper motor driver indirection to allow some stepper functions to
|
||||
* be done via SPI/I2c instead of direct pin manipulation.
|
||||
*
|
||||
* Part of Marlin
|
||||
*
|
||||
* Copyright (c) 2015 Dominik Wenger
|
||||
*/
|
||||
|
||||
#include "stepper_indirection.h"
|
||||
|
||||
#include "MarlinConfig.h"
|
||||
|
||||
//
|
||||
// TMC26X Driver objects and inits
|
||||
//
|
||||
#if ENABLED(HAVE_TMCDRIVER)
|
||||
|
||||
#include <SPI.h>
|
||||
#include <TMC26XStepper.h>
|
||||
|
||||
#define _TMC_DEFINE(ST) TMC26XStepper stepper##ST(200, ST##_ENABLE_PIN, ST##_STEP_PIN, ST##_DIR_PIN, ST##_MAX_CURRENT, ST##_SENSE_RESISTOR)
|
||||
|
||||
#if ENABLED(X_IS_TMC)
|
||||
_TMC_DEFINE(X);
|
||||
#endif
|
||||
#if ENABLED(X2_IS_TMC)
|
||||
_TMC_DEFINE(X2);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC)
|
||||
_TMC_DEFINE(Y);
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_TMC)
|
||||
_TMC_DEFINE(Y2);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_TMC)
|
||||
_TMC_DEFINE(Z);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_TMC)
|
||||
_TMC_DEFINE(Z2);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_TMC)
|
||||
_TMC_DEFINE(E0);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_TMC)
|
||||
_TMC_DEFINE(E1);
|
||||
#endif
|
||||
#if ENABLED(E2_IS_TMC)
|
||||
_TMC_DEFINE(E2);
|
||||
#endif
|
||||
#if ENABLED(E3_IS_TMC)
|
||||
_TMC_DEFINE(E3);
|
||||
#endif
|
||||
#if ENABLED(E4_IS_TMC)
|
||||
_TMC_DEFINE(E4);
|
||||
#endif
|
||||
|
||||
#define _TMC_INIT(A) do{ \
|
||||
stepper##A.setMicrosteps(A##_MICROSTEPS); \
|
||||
stepper##A.start(); \
|
||||
}while(0)
|
||||
|
||||
void tmc_init() {
|
||||
#if ENABLED(X_IS_TMC)
|
||||
_TMC_INIT(X);
|
||||
#endif
|
||||
#if ENABLED(X2_IS_TMC)
|
||||
_TMC_INIT(X2);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC)
|
||||
_TMC_INIT(Y);
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_TMC)
|
||||
_TMC_INIT(Y2);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_TMC)
|
||||
_TMC_INIT(Z);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_TMC)
|
||||
_TMC_INIT(Z2);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_TMC)
|
||||
_TMC_INIT(E0);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_TMC)
|
||||
_TMC_INIT(E1);
|
||||
#endif
|
||||
#if ENABLED(E2_IS_TMC)
|
||||
_TMC_INIT(E2);
|
||||
#endif
|
||||
#if ENABLED(E3_IS_TMC)
|
||||
_TMC_INIT(E3);
|
||||
#endif
|
||||
#if ENABLED(E4_IS_TMC)
|
||||
_TMC_INIT(E4);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // HAVE_TMCDRIVER
|
||||
|
||||
//
|
||||
// TMC2130 Driver objects and inits
|
||||
//
|
||||
#if ENABLED(HAVE_TMC2130)
|
||||
|
||||
#include <SPI.h>
|
||||
#include <TMC2130Stepper.h>
|
||||
#include "enum.h"
|
||||
|
||||
#define _TMC2130_DEFINE(ST) TMC2130Stepper stepper##ST(ST##_ENABLE_PIN, ST##_DIR_PIN, ST##_STEP_PIN, ST##_CS_PIN)
|
||||
|
||||
// Stepper objects of TMC2130 steppers used
|
||||
#if ENABLED(X_IS_TMC2130)
|
||||
_TMC2130_DEFINE(X);
|
||||
#endif
|
||||
#if ENABLED(X2_IS_TMC2130)
|
||||
_TMC2130_DEFINE(X2);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC2130)
|
||||
_TMC2130_DEFINE(Y);
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_TMC2130)
|
||||
_TMC2130_DEFINE(Y2);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_TMC2130)
|
||||
_TMC2130_DEFINE(Z);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_TMC2130)
|
||||
_TMC2130_DEFINE(Z2);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_TMC2130)
|
||||
_TMC2130_DEFINE(E0);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_TMC2130)
|
||||
_TMC2130_DEFINE(E1);
|
||||
#endif
|
||||
#if ENABLED(E2_IS_TMC2130)
|
||||
_TMC2130_DEFINE(E2);
|
||||
#endif
|
||||
#if ENABLED(E3_IS_TMC2130)
|
||||
_TMC2130_DEFINE(E3);
|
||||
#endif
|
||||
#if ENABLED(E4_IS_TMC2130)
|
||||
_TMC2130_DEFINE(E4);
|
||||
#endif
|
||||
|
||||
// Use internal reference voltage for current calculations. This is the default.
|
||||
// Following values from Trinamic's spreadsheet with values for a NEMA17 (42BYGHW609)
|
||||
// https://www.trinamic.com/products/integrated-circuits/details/tmc2130/
|
||||
void tmc2130_init(TMC2130Stepper &st, const uint16_t microsteps, const uint32_t thrs, const float &spmm) {
|
||||
st.begin();
|
||||
st.setCurrent(st.getCurrent(), R_SENSE, HOLD_MULTIPLIER);
|
||||
st.microsteps(microsteps);
|
||||
st.blank_time(36);
|
||||
st.off_time(5); // Only enables the driver if used with stealthChop
|
||||
st.interpolate(INTERPOLATE);
|
||||
st.power_down_delay(128); // ~2s until driver lowers to hold current
|
||||
st.hysterisis_start(0); // HSTRT = 1
|
||||
st.hysterisis_low(1); // HEND = -2
|
||||
st.diag1_active_high(1); // For sensorless homing
|
||||
#if ENABLED(STEALTHCHOP)
|
||||
st.stealth_freq(1); // f_pwm = 2/683 f_clk
|
||||
st.stealth_autoscale(1);
|
||||
st.stealth_gradient(5);
|
||||
st.stealth_amplitude(255);
|
||||
st.stealthChop(1);
|
||||
#if ENABLED(HYBRID_THRESHOLD)
|
||||
st.stealth_max_speed(12650000UL*st.microsteps()/(256*thrs*spmm));
|
||||
#endif
|
||||
#elif ENABLED(SENSORLESS_HOMING)
|
||||
st.coolstep_min_speed(1024UL * 1024UL - 1UL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define _TMC2130_INIT(ST, SPMM) tmc2130_init(stepper##ST, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, SPMM)
|
||||
|
||||
void tmc2130_init() {
|
||||
constexpr float steps_per_mm[] = DEFAULT_AXIS_STEPS_PER_UNIT;
|
||||
#if ENABLED(X_IS_TMC2130)
|
||||
_TMC2130_INIT( X, steps_per_mm[X_AXIS]);
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
stepperX.sg_stall_value(X_HOMING_SENSITIVITY);
|
||||
#endif
|
||||
#endif
|
||||
#if ENABLED(X2_IS_TMC2130)
|
||||
_TMC2130_INIT(X2, steps_per_mm[X_AXIS]);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_TMC2130)
|
||||
_TMC2130_INIT( Y, steps_per_mm[Y_AXIS]);
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
stepperY.sg_stall_value(Y_HOMING_SENSITIVITY);
|
||||
#endif
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_TMC2130)
|
||||
_TMC2130_INIT(Y2, steps_per_mm[Y_AXIS]);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_TMC2130)
|
||||
_TMC2130_INIT( Z, steps_per_mm[Z_AXIS]);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_TMC2130)
|
||||
_TMC2130_INIT(Z2, steps_per_mm[Z_AXIS]);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_TMC2130)
|
||||
_TMC2130_INIT(E0, steps_per_mm[E_AXIS]);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_TMC2130)
|
||||
{ constexpr int extruder = 1; _TMC2130_INIT(E1, steps_per_mm[E_AXIS_N]); }
|
||||
#endif
|
||||
#if ENABLED(E2_IS_TMC2130)
|
||||
{ constexpr int extruder = 2; _TMC2130_INIT(E2, steps_per_mm[E_AXIS_N]); }
|
||||
#endif
|
||||
#if ENABLED(E3_IS_TMC2130)
|
||||
{ constexpr int extruder = 3; _TMC2130_INIT(E3, steps_per_mm[E_AXIS_N]); }
|
||||
#endif
|
||||
#if ENABLED(E4_IS_TMC2130)
|
||||
{ constexpr int extruder = 4; _TMC2130_INIT(E4, steps_per_mm[E_AXIS_N]); }
|
||||
#endif
|
||||
|
||||
TMC2130_ADV()
|
||||
}
|
||||
#endif // HAVE_TMC2130
|
||||
|
||||
|
||||
//
|
||||
// L6470 Driver objects and inits
|
||||
//
|
||||
#if ENABLED(HAVE_L6470DRIVER)
|
||||
|
||||
#include <SPI.h>
|
||||
#include <L6470.h>
|
||||
|
||||
#define _L6470_DEFINE(ST) L6470 stepper##ST(ST##_ENABLE_PIN)
|
||||
|
||||
// L6470 Stepper objects
|
||||
#if ENABLED(X_IS_L6470)
|
||||
_L6470_DEFINE(X);
|
||||
#endif
|
||||
#if ENABLED(X2_IS_L6470)
|
||||
_L6470_DEFINE(X2);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_L6470)
|
||||
_L6470_DEFINE(Y);
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_L6470)
|
||||
_L6470_DEFINE(Y2);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_L6470)
|
||||
_L6470_DEFINE(Z);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_L6470)
|
||||
_L6470_DEFINE(Z2);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_L6470)
|
||||
_L6470_DEFINE(E0);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_L6470)
|
||||
_L6470_DEFINE(E1);
|
||||
#endif
|
||||
#if ENABLED(E2_IS_L6470)
|
||||
_L6470_DEFINE(E2);
|
||||
#endif
|
||||
#if ENABLED(E3_IS_L6470)
|
||||
_L6470_DEFINE(E3);
|
||||
#endif
|
||||
#if ENABLED(E4_IS_L6470)
|
||||
_L6470_DEFINE(E4);
|
||||
#endif
|
||||
|
||||
#define _L6470_INIT(A) do{ \
|
||||
stepper##A.init(A##_K_VAL); \
|
||||
stepper##A.softFree(); \
|
||||
stepper##A.setMicroSteps(A##_MICROSTEPS); \
|
||||
stepper##A.setOverCurrent(A##_OVERCURRENT); \
|
||||
stepper##A.setStallCurrent(A##_STALLCURRENT); \
|
||||
}while(0)
|
||||
|
||||
void L6470_init() {
|
||||
#if ENABLED(X_IS_L6470)
|
||||
_L6470_INIT(X);
|
||||
#endif
|
||||
#if ENABLED(X2_IS_L6470)
|
||||
_L6470_INIT(X2);
|
||||
#endif
|
||||
#if ENABLED(Y_IS_L6470)
|
||||
_L6470_INIT(Y);
|
||||
#endif
|
||||
#if ENABLED(Y2_IS_L6470)
|
||||
_L6470_INIT(Y2);
|
||||
#endif
|
||||
#if ENABLED(Z_IS_L6470)
|
||||
_L6470_INIT(Z);
|
||||
#endif
|
||||
#if ENABLED(Z2_IS_L6470)
|
||||
_L6470_INIT(Z2);
|
||||
#endif
|
||||
#if ENABLED(E0_IS_L6470)
|
||||
_L6470_INIT(E0);
|
||||
#endif
|
||||
#if ENABLED(E1_IS_L6470)
|
||||
_L6470_INIT(E1);
|
||||
#endif
|
||||
#if ENABLED(E2_IS_L6470)
|
||||
_L6470_INIT(E2);
|
||||
#endif
|
||||
#if ENABLED(E3_IS_L6470)
|
||||
_L6470_INIT(E3);
|
||||
#endif
|
||||
#if ENABLED(E4_IS_L6470)
|
||||
_L6470_INIT(E4);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // HAVE_L6470DRIVER
|
||||
|
485
Marlin/src/module/stepper_indirection.h
Normal file
485
Marlin/src/module/stepper_indirection.h
Normal file
@ -0,0 +1,485 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
stepper_indirection.h - stepper motor driver indirection macros
|
||||
to allow some stepper functions to be done via SPI/I2c instead of direct pin manipulation
|
||||
Part of Marlin
|
||||
|
||||
Copyright (c) 2015 Dominik Wenger
|
||||
|
||||
Marlin 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.
|
||||
|
||||
Marlin 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 Marlin. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef STEPPER_INDIRECTION_H
|
||||
#define STEPPER_INDIRECTION_H
|
||||
|
||||
#include "MarlinConfig.h"
|
||||
|
||||
// TMC26X drivers have STEP/DIR on normal pins, but ENABLE via SPI
|
||||
#if ENABLED(HAVE_TMCDRIVER)
|
||||
#include <SPI.h>
|
||||
#include <TMC26XStepper.h>
|
||||
void tmc_init();
|
||||
#endif
|
||||
|
||||
#if ENABLED(HAVE_TMC2130)
|
||||
#include <TMC2130Stepper.h>
|
||||
void tmc2130_init();
|
||||
#endif
|
||||
|
||||
// L6470 has STEP on normal pins, but DIR/ENABLE via SPI
|
||||
#if ENABLED(HAVE_L6470DRIVER)
|
||||
#include <SPI.h>
|
||||
#include <L6470.h>
|
||||
void L6470_init();
|
||||
#endif
|
||||
|
||||
// X Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(X_IS_L6470)
|
||||
extern L6470 stepperX;
|
||||
#define X_ENABLE_INIT NOOP
|
||||
#define X_ENABLE_WRITE(STATE) do{if(STATE) stepperX.Step_Clock(stepperX.getStatus() & STATUS_HIZ); else stepperX.softFree();}while(0)
|
||||
#define X_ENABLE_READ (stepperX.getStatus() & STATUS_HIZ)
|
||||
#define X_DIR_INIT NOOP
|
||||
#define X_DIR_WRITE(STATE) stepperX.Step_Clock(STATE)
|
||||
#define X_DIR_READ (stepperX.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(X_IS_TMC)
|
||||
extern TMC26XStepper stepperX;
|
||||
#define X_ENABLE_INIT NOOP
|
||||
#define X_ENABLE_WRITE(STATE) stepperX.setEnabled(STATE)
|
||||
#define X_ENABLE_READ stepperX.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(X_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperX;
|
||||
#endif
|
||||
#define X_ENABLE_INIT SET_OUTPUT(X_ENABLE_PIN)
|
||||
#define X_ENABLE_WRITE(STATE) WRITE(X_ENABLE_PIN,STATE)
|
||||
#define X_ENABLE_READ READ(X_ENABLE_PIN)
|
||||
#endif
|
||||
#define X_DIR_INIT SET_OUTPUT(X_DIR_PIN)
|
||||
#define X_DIR_WRITE(STATE) WRITE(X_DIR_PIN,STATE)
|
||||
#define X_DIR_READ READ(X_DIR_PIN)
|
||||
#endif
|
||||
#define X_STEP_INIT SET_OUTPUT(X_STEP_PIN)
|
||||
#define X_STEP_WRITE(STATE) WRITE(X_STEP_PIN,STATE)
|
||||
#define X_STEP_READ READ(X_STEP_PIN)
|
||||
|
||||
// Y Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(Y_IS_L6470)
|
||||
extern L6470 stepperY;
|
||||
#define Y_ENABLE_INIT NOOP
|
||||
#define Y_ENABLE_WRITE(STATE) do{if(STATE) stepperY.Step_Clock(stepperY.getStatus() & STATUS_HIZ); else stepperY.softFree();}while(0)
|
||||
#define Y_ENABLE_READ (stepperY.getStatus() & STATUS_HIZ)
|
||||
#define Y_DIR_INIT NOOP
|
||||
#define Y_DIR_WRITE(STATE) stepperY.Step_Clock(STATE)
|
||||
#define Y_DIR_READ (stepperY.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(Y_IS_TMC)
|
||||
extern TMC26XStepper stepperY;
|
||||
#define Y_ENABLE_INIT NOOP
|
||||
#define Y_ENABLE_WRITE(STATE) stepperY.setEnabled(STATE)
|
||||
#define Y_ENABLE_READ stepperY.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(Y_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperY;
|
||||
#endif
|
||||
#define Y_ENABLE_INIT SET_OUTPUT(Y_ENABLE_PIN)
|
||||
#define Y_ENABLE_WRITE(STATE) WRITE(Y_ENABLE_PIN,STATE)
|
||||
#define Y_ENABLE_READ READ(Y_ENABLE_PIN)
|
||||
#endif
|
||||
#define Y_DIR_INIT SET_OUTPUT(Y_DIR_PIN)
|
||||
#define Y_DIR_WRITE(STATE) WRITE(Y_DIR_PIN,STATE)
|
||||
#define Y_DIR_READ READ(Y_DIR_PIN)
|
||||
#endif
|
||||
#define Y_STEP_INIT SET_OUTPUT(Y_STEP_PIN)
|
||||
#define Y_STEP_WRITE(STATE) WRITE(Y_STEP_PIN,STATE)
|
||||
#define Y_STEP_READ READ(Y_STEP_PIN)
|
||||
|
||||
// Z Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(Z_IS_L6470)
|
||||
extern L6470 stepperZ;
|
||||
#define Z_ENABLE_INIT NOOP
|
||||
#define Z_ENABLE_WRITE(STATE) do{if(STATE) stepperZ.Step_Clock(stepperZ.getStatus() & STATUS_HIZ); else stepperZ.softFree();}while(0)
|
||||
#define Z_ENABLE_READ (stepperZ.getStatus() & STATUS_HIZ)
|
||||
#define Z_DIR_INIT NOOP
|
||||
#define Z_DIR_WRITE(STATE) stepperZ.Step_Clock(STATE)
|
||||
#define Z_DIR_READ (stepperZ.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(Z_IS_TMC)
|
||||
extern TMC26XStepper stepperZ;
|
||||
#define Z_ENABLE_INIT NOOP
|
||||
#define Z_ENABLE_WRITE(STATE) stepperZ.setEnabled(STATE)
|
||||
#define Z_ENABLE_READ stepperZ.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(Z_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperZ;
|
||||
#endif
|
||||
#define Z_ENABLE_INIT SET_OUTPUT(Z_ENABLE_PIN)
|
||||
#define Z_ENABLE_WRITE(STATE) WRITE(Z_ENABLE_PIN,STATE)
|
||||
#define Z_ENABLE_READ READ(Z_ENABLE_PIN)
|
||||
#endif
|
||||
#define Z_DIR_INIT SET_OUTPUT(Z_DIR_PIN)
|
||||
#define Z_DIR_WRITE(STATE) WRITE(Z_DIR_PIN,STATE)
|
||||
#define Z_DIR_READ READ(Z_DIR_PIN)
|
||||
#endif
|
||||
#define Z_STEP_INIT SET_OUTPUT(Z_STEP_PIN)
|
||||
#define Z_STEP_WRITE(STATE) WRITE(Z_STEP_PIN,STATE)
|
||||
#define Z_STEP_READ READ(Z_STEP_PIN)
|
||||
|
||||
// X2 Stepper
|
||||
#if HAS_X2_ENABLE
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(X2_IS_L6470)
|
||||
extern L6470 stepperX2;
|
||||
#define X2_ENABLE_INIT NOOP
|
||||
#define X2_ENABLE_WRITE(STATE) do{if(STATE) stepperX2.Step_Clock(stepperX2.getStatus() & STATUS_HIZ); else stepperX2.softFree();}while(0)
|
||||
#define X2_ENABLE_READ (stepperX2.getStatus() & STATUS_HIZ)
|
||||
#define X2_DIR_INIT NOOP
|
||||
#define X2_DIR_WRITE(STATE) stepperX2.Step_Clock(STATE)
|
||||
#define X2_DIR_READ (stepperX2.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(X2_IS_TMC)
|
||||
extern TMC26XStepper stepperX2;
|
||||
#define X2_ENABLE_INIT NOOP
|
||||
#define X2_ENABLE_WRITE(STATE) stepperX2.setEnabled(STATE)
|
||||
#define X2_ENABLE_READ stepperX2.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(X2_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperX2;
|
||||
#endif
|
||||
#define X2_ENABLE_INIT SET_OUTPUT(X2_ENABLE_PIN)
|
||||
#define X2_ENABLE_WRITE(STATE) WRITE(X2_ENABLE_PIN,STATE)
|
||||
#define X2_ENABLE_READ READ(X2_ENABLE_PIN)
|
||||
#endif
|
||||
#define X2_DIR_INIT SET_OUTPUT(X2_DIR_PIN)
|
||||
#define X2_DIR_WRITE(STATE) WRITE(X2_DIR_PIN,STATE)
|
||||
#define X2_DIR_READ READ(X2_DIR_PIN)
|
||||
#endif
|
||||
#define X2_STEP_INIT SET_OUTPUT(X2_STEP_PIN)
|
||||
#define X2_STEP_WRITE(STATE) WRITE(X2_STEP_PIN,STATE)
|
||||
#define X2_STEP_READ READ(X2_STEP_PIN)
|
||||
#endif
|
||||
|
||||
// Y2 Stepper
|
||||
#if HAS_Y2_ENABLE
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(Y2_IS_L6470)
|
||||
extern L6470 stepperY2;
|
||||
#define Y2_ENABLE_INIT NOOP
|
||||
#define Y2_ENABLE_WRITE(STATE) do{if(STATE) stepperY2.Step_Clock(stepperY2.getStatus() & STATUS_HIZ); else stepperY2.softFree();}while(0)
|
||||
#define Y2_ENABLE_READ (stepperY2.getStatus() & STATUS_HIZ)
|
||||
#define Y2_DIR_INIT NOOP
|
||||
#define Y2_DIR_WRITE(STATE) stepperY2.Step_Clock(STATE)
|
||||
#define Y2_DIR_READ (stepperY2.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(Y2_IS_TMC)
|
||||
extern TMC26XStepper stepperY2;
|
||||
#define Y2_ENABLE_INIT NOOP
|
||||
#define Y2_ENABLE_WRITE(STATE) stepperY2.setEnabled(STATE)
|
||||
#define Y2_ENABLE_READ stepperY2.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(Y2_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperY2;
|
||||
#endif
|
||||
#define Y2_ENABLE_INIT SET_OUTPUT(Y2_ENABLE_PIN)
|
||||
#define Y2_ENABLE_WRITE(STATE) WRITE(Y2_ENABLE_PIN,STATE)
|
||||
#define Y2_ENABLE_READ READ(Y2_ENABLE_PIN)
|
||||
#endif
|
||||
#define Y2_DIR_INIT SET_OUTPUT(Y2_DIR_PIN)
|
||||
#define Y2_DIR_WRITE(STATE) WRITE(Y2_DIR_PIN,STATE)
|
||||
#define Y2_DIR_READ READ(Y2_DIR_PIN)
|
||||
#endif
|
||||
#define Y2_STEP_INIT SET_OUTPUT(Y2_STEP_PIN)
|
||||
#define Y2_STEP_WRITE(STATE) WRITE(Y2_STEP_PIN,STATE)
|
||||
#define Y2_STEP_READ READ(Y2_STEP_PIN)
|
||||
#endif
|
||||
|
||||
// Z2 Stepper
|
||||
#if HAS_Z2_ENABLE
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(Z2_IS_L6470)
|
||||
extern L6470 stepperZ2;
|
||||
#define Z2_ENABLE_INIT NOOP
|
||||
#define Z2_ENABLE_WRITE(STATE) do{if(STATE) stepperZ2.Step_Clock(stepperZ2.getStatus() & STATUS_HIZ); else stepperZ2.softFree();}while(0)
|
||||
#define Z2_ENABLE_READ (stepperZ2.getStatus() & STATUS_HIZ)
|
||||
#define Z2_DIR_INIT NOOP
|
||||
#define Z2_DIR_WRITE(STATE) stepperZ2.Step_Clock(STATE)
|
||||
#define Z2_DIR_READ (stepperZ2.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(Z2_IS_TMC)
|
||||
extern TMC26XStepper stepperZ2;
|
||||
#define Z2_ENABLE_INIT NOOP
|
||||
#define Z2_ENABLE_WRITE(STATE) stepperZ2.setEnabled(STATE)
|
||||
#define Z2_ENABLE_READ stepperZ2.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(Z2_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperZ2;
|
||||
#endif
|
||||
#define Z2_ENABLE_INIT SET_OUTPUT(Z2_ENABLE_PIN)
|
||||
#define Z2_ENABLE_WRITE(STATE) WRITE(Z2_ENABLE_PIN,STATE)
|
||||
#define Z2_ENABLE_READ READ(Z2_ENABLE_PIN)
|
||||
#endif
|
||||
#define Z2_DIR_INIT SET_OUTPUT(Z2_DIR_PIN)
|
||||
#define Z2_DIR_WRITE(STATE) WRITE(Z2_DIR_PIN,STATE)
|
||||
#define Z2_DIR_READ READ(Z2_DIR_PIN)
|
||||
#endif
|
||||
#define Z2_STEP_INIT SET_OUTPUT(Z2_STEP_PIN)
|
||||
#define Z2_STEP_WRITE(STATE) WRITE(Z2_STEP_PIN,STATE)
|
||||
#define Z2_STEP_READ READ(Z2_STEP_PIN)
|
||||
#endif
|
||||
|
||||
// E0 Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(E0_IS_L6470)
|
||||
extern L6470 stepperE0;
|
||||
#define E0_ENABLE_INIT NOOP
|
||||
#define E0_ENABLE_WRITE(STATE) do{if(STATE) stepperE0.Step_Clock(stepperE0.getStatus() & STATUS_HIZ); else stepperE0.softFree();}while(0)
|
||||
#define E0_ENABLE_READ (stepperE0.getStatus() & STATUS_HIZ)
|
||||
#define E0_DIR_INIT NOOP
|
||||
#define E0_DIR_WRITE(STATE) stepperE0.Step_Clock(STATE)
|
||||
#define E0_DIR_READ (stepperE0.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(E0_IS_TMC)
|
||||
extern TMC26XStepper stepperE0;
|
||||
#define E0_ENABLE_INIT NOOP
|
||||
#define E0_ENABLE_WRITE(STATE) stepperE0.setEnabled(STATE)
|
||||
#define E0_ENABLE_READ stepperE0.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(E0_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperE0;
|
||||
#endif
|
||||
#define E0_ENABLE_INIT SET_OUTPUT(E0_ENABLE_PIN)
|
||||
#define E0_ENABLE_WRITE(STATE) WRITE(E0_ENABLE_PIN,STATE)
|
||||
#define E0_ENABLE_READ READ(E0_ENABLE_PIN)
|
||||
#endif
|
||||
#define E0_DIR_INIT SET_OUTPUT(E0_DIR_PIN)
|
||||
#define E0_DIR_WRITE(STATE) WRITE(E0_DIR_PIN,STATE)
|
||||
#define E0_DIR_READ READ(E0_DIR_PIN)
|
||||
#endif
|
||||
#define E0_STEP_INIT SET_OUTPUT(E0_STEP_PIN)
|
||||
#define E0_STEP_WRITE(STATE) WRITE(E0_STEP_PIN,STATE)
|
||||
#define E0_STEP_READ READ(E0_STEP_PIN)
|
||||
|
||||
// E1 Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(E1_IS_L6470)
|
||||
extern L6470 stepperE1;
|
||||
#define E1_ENABLE_INIT NOOP
|
||||
#define E1_ENABLE_WRITE(STATE) do{if(STATE) stepperE1.Step_Clock(stepperE1.getStatus() & STATUS_HIZ); else stepperE1.softFree();}while(0)
|
||||
#define E1_ENABLE_READ (stepperE1.getStatus() & STATUS_HIZ)
|
||||
#define E1_DIR_INIT NOOP
|
||||
#define E1_DIR_WRITE(STATE) stepperE1.Step_Clock(STATE)
|
||||
#define E1_DIR_READ (stepperE1.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(E1_IS_TMC)
|
||||
extern TMC26XStepper stepperE1;
|
||||
#define E1_ENABLE_INIT NOOP
|
||||
#define E1_ENABLE_WRITE(STATE) stepperE1.setEnabled(STATE)
|
||||
#define E1_ENABLE_READ stepperE1.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(E1_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperE1;
|
||||
#endif
|
||||
#define E1_ENABLE_INIT SET_OUTPUT(E1_ENABLE_PIN)
|
||||
#define E1_ENABLE_WRITE(STATE) WRITE(E1_ENABLE_PIN,STATE)
|
||||
#define E1_ENABLE_READ READ(E1_ENABLE_PIN)
|
||||
#endif
|
||||
#define E1_DIR_INIT SET_OUTPUT(E1_DIR_PIN)
|
||||
#define E1_DIR_WRITE(STATE) WRITE(E1_DIR_PIN,STATE)
|
||||
#define E1_DIR_READ READ(E1_DIR_PIN)
|
||||
#endif
|
||||
#define E1_STEP_INIT SET_OUTPUT(E1_STEP_PIN)
|
||||
#define E1_STEP_WRITE(STATE) WRITE(E1_STEP_PIN,STATE)
|
||||
#define E1_STEP_READ READ(E1_STEP_PIN)
|
||||
|
||||
// E2 Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(E2_IS_L6470)
|
||||
extern L6470 stepperE2;
|
||||
#define E2_ENABLE_INIT NOOP
|
||||
#define E2_ENABLE_WRITE(STATE) do{if(STATE) stepperE2.Step_Clock(stepperE2.getStatus() & STATUS_HIZ); else stepperE2.softFree();}while(0)
|
||||
#define E2_ENABLE_READ (stepperE2.getStatus() & STATUS_HIZ)
|
||||
#define E2_DIR_INIT NOOP
|
||||
#define E2_DIR_WRITE(STATE) stepperE2.Step_Clock(STATE)
|
||||
#define E2_DIR_READ (stepperE2.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(E2_IS_TMC)
|
||||
extern TMC26XStepper stepperE2;
|
||||
#define E2_ENABLE_INIT NOOP
|
||||
#define E2_ENABLE_WRITE(STATE) stepperE2.setEnabled(STATE)
|
||||
#define E2_ENABLE_READ stepperE2.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(E2_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperE2;
|
||||
#endif
|
||||
#define E2_ENABLE_INIT SET_OUTPUT(E2_ENABLE_PIN)
|
||||
#define E2_ENABLE_WRITE(STATE) WRITE(E2_ENABLE_PIN,STATE)
|
||||
#define E2_ENABLE_READ READ(E2_ENABLE_PIN)
|
||||
#endif
|
||||
#define E2_DIR_INIT SET_OUTPUT(E2_DIR_PIN)
|
||||
#define E2_DIR_WRITE(STATE) WRITE(E2_DIR_PIN,STATE)
|
||||
#define E2_DIR_READ READ(E2_DIR_PIN)
|
||||
#endif
|
||||
#define E2_STEP_INIT SET_OUTPUT(E2_STEP_PIN)
|
||||
#define E2_STEP_WRITE(STATE) WRITE(E2_STEP_PIN,STATE)
|
||||
#define E2_STEP_READ READ(E2_STEP_PIN)
|
||||
|
||||
// E3 Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(E3_IS_L6470)
|
||||
extern L6470 stepperE3;
|
||||
#define E3_ENABLE_INIT NOOP
|
||||
#define E3_ENABLE_WRITE(STATE) do{if(STATE) stepperE3.Step_Clock(stepperE3.getStatus() & STATUS_HIZ); else stepperE3.softFree();}while(0)
|
||||
#define E3_ENABLE_READ (stepperE3.getStatus() & STATUS_HIZ)
|
||||
#define E3_DIR_INIT NOOP
|
||||
#define E3_DIR_WRITE(STATE) stepperE3.Step_Clock(STATE)
|
||||
#define E3_DIR_READ (stepperE3.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(E3_IS_TMC)
|
||||
extern TMC26XStepper stepperE3;
|
||||
#define E3_ENABLE_INIT NOOP
|
||||
#define E3_ENABLE_WRITE(STATE) stepperE3.setEnabled(STATE)
|
||||
#define E3_ENABLE_READ stepperE3.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(E3_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperE3;
|
||||
#endif
|
||||
#define E3_ENABLE_INIT SET_OUTPUT(E3_ENABLE_PIN)
|
||||
#define E3_ENABLE_WRITE(STATE) WRITE(E3_ENABLE_PIN,STATE)
|
||||
#define E3_ENABLE_READ READ(E3_ENABLE_PIN)
|
||||
#endif
|
||||
#define E3_DIR_INIT SET_OUTPUT(E3_DIR_PIN)
|
||||
#define E3_DIR_WRITE(STATE) WRITE(E3_DIR_PIN,STATE)
|
||||
#define E3_DIR_READ READ(E3_DIR_PIN)
|
||||
#endif
|
||||
#define E3_STEP_INIT SET_OUTPUT(E3_STEP_PIN)
|
||||
#define E3_STEP_WRITE(STATE) WRITE(E3_STEP_PIN,STATE)
|
||||
#define E3_STEP_READ READ(E3_STEP_PIN)
|
||||
|
||||
// E4 Stepper
|
||||
#if ENABLED(HAVE_L6470DRIVER) && ENABLED(E4_IS_L6470)
|
||||
extern L6470 stepperE4;
|
||||
#define E4_ENABLE_INIT NOOP
|
||||
#define E4_ENABLE_WRITE(STATE) do{ if (STATE) stepperE4.Step_Clock(stepperE4.getStatus() & STATUS_HIZ); else stepperE4.softFree(); }while(0)
|
||||
#define E4_ENABLE_READ (stepperE4.getStatus() & STATUS_HIZ)
|
||||
#define E4_DIR_INIT NOOP
|
||||
#define E4_DIR_WRITE(STATE) stepperE4.Step_Clock(STATE)
|
||||
#define E4_DIR_READ (stepperE4.getStatus() & STATUS_DIR)
|
||||
#else
|
||||
#if ENABLED(HAVE_TMCDRIVER) && ENABLED(E4_IS_TMC)
|
||||
extern TMC26XStepper stepperE4;
|
||||
#define E4_ENABLE_INIT NOOP
|
||||
#define E4_ENABLE_WRITE(STATE) stepperE4.setEnabled(STATE)
|
||||
#define E4_ENABLE_READ stepperE4.isEnabled()
|
||||
#else
|
||||
#if ENABLED(HAVE_TMC2130) && ENABLED(E4_IS_TMC2130)
|
||||
extern TMC2130Stepper stepperE4;
|
||||
#endif
|
||||
#define E4_ENABLE_INIT SET_OUTPUT(E4_ENABLE_PIN)
|
||||
#define E4_ENABLE_WRITE(STATE) WRITE(E4_ENABLE_PIN,STATE)
|
||||
#define E4_ENABLE_READ READ(E4_ENABLE_PIN)
|
||||
#endif
|
||||
#define E4_DIR_INIT SET_OUTPUT(E4_DIR_PIN)
|
||||
#define E4_DIR_WRITE(STATE) WRITE(E4_DIR_PIN,STATE)
|
||||
#define E4_DIR_READ READ(E4_DIR_PIN)
|
||||
#endif
|
||||
#define E4_STEP_INIT SET_OUTPUT(E4_STEP_PIN)
|
||||
#define E4_STEP_WRITE(STATE) WRITE(E4_STEP_PIN,STATE)
|
||||
#define E4_STEP_READ READ(E4_STEP_PIN)
|
||||
|
||||
/**
|
||||
* Extruder indirection for the single E axis
|
||||
*/
|
||||
#if ENABLED(SWITCHING_EXTRUDER)
|
||||
#if EXTRUDERS == 2
|
||||
#define E_STEP_WRITE(v) E0_STEP_WRITE(v)
|
||||
#define NORM_E_DIR() E0_DIR_WRITE(current_block->active_extruder ? INVERT_E0_DIR : !INVERT_E0_DIR)
|
||||
#define REV_E_DIR() E0_DIR_WRITE(current_block->active_extruder ? !INVERT_E0_DIR : INVERT_E0_DIR)
|
||||
#elif EXTRUDERS > 4
|
||||
#define E_STEP_WRITE(v) { if (current_block->active_extruder < 2) E0_STEP_WRITE(v); else if (current_block->active_extruder < 4) E1_STEP_WRITE(v); else E2_STEP_WRITE(v); }
|
||||
#define NORM_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#define REV_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#elif EXTRUDERS > 2
|
||||
#define E_STEP_WRITE(v) { if (current_block->active_extruder < 2) E0_STEP_WRITE(v); else if (current_block->active_extruder < 4) E1_STEP_WRITE(v); else E1_STEP_WRITE(v); }
|
||||
#define NORM_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#define REV_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#endif
|
||||
#elif EXTRUDERS > 4
|
||||
#define E_STEP_WRITE(v) { switch (current_block->active_extruder) { 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); } }
|
||||
#define NORM_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#define REV_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#elif EXTRUDERS > 3
|
||||
#define E_STEP_WRITE(v) { switch (current_block->active_extruder) { 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); } }
|
||||
#define NORM_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#define REV_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#elif EXTRUDERS > 2
|
||||
#define E_STEP_WRITE(v) { switch (current_block->active_extruder) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); } }
|
||||
#define NORM_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#define REV_E_DIR() { switch (current_block->active_extruder) { 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); } }
|
||||
#elif EXTRUDERS > 1
|
||||
#if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
|
||||
#define E_STEP_WRITE(v) { if (extruder_duplication_enabled) { E0_STEP_WRITE(v); E1_STEP_WRITE(v); } else if (current_block->active_extruder == 0) { E0_STEP_WRITE(v); } else { E1_STEP_WRITE(v); } }
|
||||
#define NORM_E_DIR() { if (extruder_duplication_enabled) { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); } else if (current_block->active_extruder == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }
|
||||
#define REV_E_DIR() { if (extruder_duplication_enabled) { E0_DIR_WRITE(INVERT_E0_DIR); E1_DIR_WRITE(INVERT_E1_DIR); } else if (current_block->active_extruder == 0) { E0_DIR_WRITE(INVERT_E0_DIR); } else { E1_DIR_WRITE(INVERT_E1_DIR); } }
|
||||
#else
|
||||
#define E_STEP_WRITE(v) { if (current_block->active_extruder == 0) { E0_STEP_WRITE(v); } else { E1_STEP_WRITE(v); } }
|
||||
#define NORM_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(!INVERT_E0_DIR); } else { E1_DIR_WRITE(!INVERT_E1_DIR); } }
|
||||
#define REV_E_DIR() { if (current_block->active_extruder == 0) { E0_DIR_WRITE(INVERT_E0_DIR); } else { E1_DIR_WRITE(INVERT_E1_DIR); } }
|
||||
#endif
|
||||
#elif ENABLED(MIXING_EXTRUDER)
|
||||
#define E_STEP_WRITE(v) NOOP /* not used for mixing extruders! */
|
||||
#if MIXING_STEPPERS > 4
|
||||
#define En_STEP_WRITE(n,v) { switch (n) { 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); } }
|
||||
#define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); E3_DIR_WRITE(!INVERT_E3_DIR); E4_DIR_WRITE(!INVERT_E4_DIR); }
|
||||
#define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); E3_DIR_WRITE( INVERT_E3_DIR); E4_DIR_WRITE( INVERT_E4_DIR); }
|
||||
#elif MIXING_STEPPERS > 3
|
||||
#define En_STEP_WRITE(n,v) { switch (n) { 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); } }
|
||||
#define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); E3_DIR_WRITE(!INVERT_E3_DIR); }
|
||||
#define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); E3_DIR_WRITE( INVERT_E3_DIR); }
|
||||
#elif MIXING_STEPPERS > 2
|
||||
#define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); break; case 2: E2_STEP_WRITE(v); } }
|
||||
#define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); E2_DIR_WRITE(!INVERT_E2_DIR); }
|
||||
#define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); E2_DIR_WRITE( INVERT_E2_DIR); }
|
||||
#else
|
||||
#define En_STEP_WRITE(n,v) { switch (n) { case 0: E0_STEP_WRITE(v); break; case 1: E1_STEP_WRITE(v); } }
|
||||
#define NORM_E_DIR() { E0_DIR_WRITE(!INVERT_E0_DIR); E1_DIR_WRITE(!INVERT_E1_DIR); }
|
||||
#define REV_E_DIR() { E0_DIR_WRITE( INVERT_E0_DIR); E1_DIR_WRITE( INVERT_E1_DIR); }
|
||||
#endif
|
||||
#else
|
||||
#define E_STEP_WRITE(v) E0_STEP_WRITE(v)
|
||||
#if ENABLED(MK2_MULTIPLEXER)
|
||||
// Even-numbered steppers are reversed
|
||||
#define NORM_E_DIR() E0_DIR_WRITE(TEST(current_block->active_extruder, 0) ? !INVERT_E0_DIR: INVERT_E0_DIR)
|
||||
#define REV_E_DIR() E0_DIR_WRITE(TEST(current_block->active_extruder, 0) ? INVERT_E0_DIR: !INVERT_E0_DIR)
|
||||
#else
|
||||
#define NORM_E_DIR() E0_DIR_WRITE(!INVERT_E0_DIR)
|
||||
#define REV_E_DIR() E0_DIR_WRITE(INVERT_E0_DIR)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // STEPPER_INDIRECTION_H
|
2122
Marlin/src/module/temperature.cpp
Normal file
2122
Marlin/src/module/temperature.cpp
Normal file
File diff suppressed because it is too large
Load Diff
578
Marlin/src/module/temperature.h
Normal file
578
Marlin/src/module/temperature.h
Normal file
@ -0,0 +1,578 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* temperature.h - temperature controller
|
||||
*/
|
||||
|
||||
#ifndef TEMPERATURE_H
|
||||
#define TEMPERATURE_H
|
||||
|
||||
#include "thermistortables.h"
|
||||
|
||||
#include "MarlinConfig.h"
|
||||
|
||||
#if ENABLED(PID_EXTRUSION_SCALING)
|
||||
#include "stepper.h"
|
||||
#endif
|
||||
|
||||
#ifndef SOFT_PWM_SCALE
|
||||
#define SOFT_PWM_SCALE 0
|
||||
#endif
|
||||
|
||||
#define HOTEND_LOOP() for (int8_t e = 0; e < HOTENDS; e++)
|
||||
|
||||
#if HOTENDS == 1
|
||||
#define HOTEND_INDEX 0
|
||||
#define EXTRUDER_IDX 0
|
||||
#else
|
||||
#define HOTEND_INDEX e
|
||||
#define EXTRUDER_IDX active_extruder
|
||||
#endif
|
||||
|
||||
/**
|
||||
* States for ADC reading in the ISR
|
||||
*/
|
||||
enum ADCSensorState {
|
||||
#if HAS_TEMP_0
|
||||
PrepareTemp_0,
|
||||
MeasureTemp_0,
|
||||
#endif
|
||||
#if HAS_TEMP_1
|
||||
PrepareTemp_1,
|
||||
MeasureTemp_1,
|
||||
#endif
|
||||
#if HAS_TEMP_2
|
||||
PrepareTemp_2,
|
||||
MeasureTemp_2,
|
||||
#endif
|
||||
#if HAS_TEMP_3
|
||||
PrepareTemp_3,
|
||||
MeasureTemp_3,
|
||||
#endif
|
||||
#if HAS_TEMP_4
|
||||
PrepareTemp_4,
|
||||
MeasureTemp_4,
|
||||
#endif
|
||||
#if HAS_TEMP_BED
|
||||
PrepareTemp_BED,
|
||||
MeasureTemp_BED,
|
||||
#endif
|
||||
#if ENABLED(FILAMENT_WIDTH_SENSOR)
|
||||
Prepare_FILWIDTH,
|
||||
Measure_FILWIDTH,
|
||||
#endif
|
||||
#if ENABLED(ADC_KEYPAD)
|
||||
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_HEATER_BED
|
||||
constexpr int16_t target_temperature_bed = 0;
|
||||
#endif
|
||||
|
||||
class Temperature {
|
||||
|
||||
public:
|
||||
|
||||
static float current_temperature[HOTENDS],
|
||||
current_temperature_bed;
|
||||
static int16_t current_temperature_raw[HOTENDS],
|
||||
target_temperature[HOTENDS],
|
||||
current_temperature_bed_raw;
|
||||
|
||||
#if HAS_HEATER_BED
|
||||
static int16_t target_temperature_bed;
|
||||
#endif
|
||||
|
||||
static volatile bool in_temp_isr;
|
||||
|
||||
static uint8_t soft_pwm_amount[HOTENDS],
|
||||
soft_pwm_amount_bed;
|
||||
|
||||
#if ENABLED(FAN_SOFT_PWM)
|
||||
static uint8_t soft_pwm_amount_fan[FAN_COUNT],
|
||||
soft_pwm_count_fan[FAN_COUNT];
|
||||
#endif
|
||||
|
||||
#if ENABLED(PIDTEMP) || ENABLED(PIDTEMPBED)
|
||||
#define PID_dT ((OVERSAMPLENR * float(ACTUAL_ADC_SAMPLES)) / TEMP_TIMER_FREQUENCY)
|
||||
#endif
|
||||
|
||||
#if ENABLED(PIDTEMP)
|
||||
|
||||
#if ENABLED(PID_PARAMS_PER_HOTEND) && HOTENDS > 1
|
||||
|
||||
static float Kp[HOTENDS], Ki[HOTENDS], Kd[HOTENDS];
|
||||
#if ENABLED(PID_EXTRUSION_SCALING)
|
||||
static float Kc[HOTENDS];
|
||||
#endif
|
||||
#define PID_PARAM(param, h) Temperature::param[h]
|
||||
|
||||
#else
|
||||
|
||||
static float Kp, Ki, Kd;
|
||||
#if ENABLED(PID_EXTRUSION_SCALING)
|
||||
static float Kc;
|
||||
#endif
|
||||
#define PID_PARAM(param, h) Temperature::param
|
||||
|
||||
#endif // PID_PARAMS_PER_HOTEND
|
||||
|
||||
// Apply the scale factors to the PID values
|
||||
#define scalePID_i(i) ( (i) * PID_dT )
|
||||
#define unscalePID_i(i) ( (i) / PID_dT )
|
||||
#define scalePID_d(d) ( (d) / PID_dT )
|
||||
#define unscalePID_d(d) ( (d) * PID_dT )
|
||||
|
||||
#endif
|
||||
|
||||
#if ENABLED(PIDTEMPBED)
|
||||
static float bedKp, bedKi, bedKd;
|
||||
#endif
|
||||
|
||||
#if ENABLED(BABYSTEPPING)
|
||||
static volatile int babystepsTodo[3];
|
||||
#endif
|
||||
|
||||
#if WATCH_HOTENDS
|
||||
static uint16_t watch_target_temp[HOTENDS];
|
||||
static millis_t watch_heater_next_ms[HOTENDS];
|
||||
#endif
|
||||
|
||||
#if WATCH_THE_BED
|
||||
static uint16_t watch_target_bed_temp;
|
||||
static millis_t watch_bed_next_ms;
|
||||
#endif
|
||||
|
||||
#if ENABLED(PREVENT_COLD_EXTRUSION)
|
||||
static bool allow_cold_extrude;
|
||||
static int16_t extrude_min_temp;
|
||||
static bool tooColdToExtrude(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return allow_cold_extrude ? false : degHotend(HOTEND_INDEX) < extrude_min_temp;
|
||||
}
|
||||
#else
|
||||
static bool tooColdToExtrude(uint8_t e) { UNUSED(e); return false; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
|
||||
static uint16_t redundant_temperature_raw;
|
||||
static float redundant_temperature;
|
||||
#endif
|
||||
|
||||
static volatile bool temp_meas_ready;
|
||||
|
||||
#if ENABLED(PIDTEMP)
|
||||
static float temp_iState[HOTENDS],
|
||||
temp_dState[HOTENDS],
|
||||
pTerm[HOTENDS],
|
||||
iTerm[HOTENDS],
|
||||
dTerm[HOTENDS];
|
||||
|
||||
#if ENABLED(PID_EXTRUSION_SCALING)
|
||||
static float cTerm[HOTENDS];
|
||||
static long last_e_position;
|
||||
static long lpq[LPQ_MAX_LEN];
|
||||
static int lpq_ptr;
|
||||
#endif
|
||||
|
||||
static float pid_error[HOTENDS];
|
||||
static bool pid_reset[HOTENDS];
|
||||
#endif
|
||||
|
||||
#if ENABLED(PIDTEMPBED)
|
||||
static float temp_iState_bed,
|
||||
temp_dState_bed,
|
||||
pTerm_bed,
|
||||
iTerm_bed,
|
||||
dTerm_bed,
|
||||
pid_error_bed;
|
||||
#else
|
||||
static millis_t next_bed_check_ms;
|
||||
#endif
|
||||
|
||||
static uint16_t raw_temp_value[MAX_EXTRUDERS],
|
||||
raw_temp_bed_value;
|
||||
|
||||
// Init min and max temp with extreme values to prevent false errors during startup
|
||||
static int16_t minttemp_raw[HOTENDS],
|
||||
maxttemp_raw[HOTENDS],
|
||||
minttemp[HOTENDS],
|
||||
maxttemp[HOTENDS];
|
||||
|
||||
#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
|
||||
|
||||
#ifdef BED_MINTEMP
|
||||
static int16_t bed_minttemp_raw;
|
||||
#endif
|
||||
|
||||
#ifdef BED_MAXTEMP
|
||||
static int16_t bed_maxttemp_raw;
|
||||
#endif
|
||||
|
||||
#if ENABLED(FILAMENT_WIDTH_SENSOR)
|
||||
static int8_t meas_shift_index; // Index of a delayed sample in buffer
|
||||
#endif
|
||||
|
||||
#if HAS_AUTO_FAN
|
||||
static millis_t next_auto_fan_check_ms;
|
||||
#endif
|
||||
|
||||
#if ENABLED(FILAMENT_WIDTH_SENSOR)
|
||||
static uint16_t current_raw_filwidth; // Measured filament diameter - one extruder only
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBING_HEATERS_OFF)
|
||||
static bool paused;
|
||||
#endif
|
||||
|
||||
#if HEATER_IDLE_HANDLER
|
||||
static millis_t heater_idle_timeout_ms[HOTENDS];
|
||||
static bool heater_idle_timeout_exceeded[HOTENDS];
|
||||
#if HAS_TEMP_BED
|
||||
static millis_t bed_idle_timeout_ms;
|
||||
static bool bed_idle_timeout_exceeded;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
#if ENABLED(ADC_KEYPAD)
|
||||
static uint32_t current_ADCKey_raw;
|
||||
static uint8_t ADCKey_count;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Instance Methods
|
||||
*/
|
||||
|
||||
Temperature();
|
||||
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Static (class) methods
|
||||
*/
|
||||
static float analog2temp(int raw, uint8_t e);
|
||||
static float analog2tempBed(int raw);
|
||||
|
||||
/**
|
||||
* Called from the Temperature ISR
|
||||
*/
|
||||
static void isr();
|
||||
|
||||
/**
|
||||
* 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(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return preheat_end_time[HOTEND_INDEX] && PENDING(millis(), preheat_end_time[HOTEND_INDEX]);
|
||||
}
|
||||
static void start_preheat_time(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
preheat_end_time[HOTEND_INDEX] = millis() + MILLISECONDS_PREHEAT_TIME;
|
||||
}
|
||||
static void reset_preheat_time(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
preheat_end_time[HOTEND_INDEX] = 0;
|
||||
}
|
||||
#else
|
||||
#define is_preheating(n) (false)
|
||||
#endif
|
||||
|
||||
#if ENABLED(FILAMENT_WIDTH_SENSOR)
|
||||
static float analog2widthFil(); // Convert raw Filament Width to millimeters
|
||||
static int widthFil_to_size_ratio(); // Convert raw Filament Width to an extrusion ratio
|
||||
#endif
|
||||
|
||||
|
||||
//high level conversion routines, for use outside of temperature.cpp
|
||||
//inline so that there is no performance decrease.
|
||||
//deg=degreeCelsius
|
||||
|
||||
static float degHotend(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return current_temperature[HOTEND_INDEX];
|
||||
}
|
||||
static float degBed() { return current_temperature_bed; }
|
||||
|
||||
#if ENABLED(SHOW_TEMP_ADC_VALUES)
|
||||
static int16_t rawHotendTemp(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return current_temperature_raw[HOTEND_INDEX];
|
||||
}
|
||||
static int16_t rawBedTemp() { return current_temperature_bed_raw; }
|
||||
#endif
|
||||
|
||||
static int16_t degTargetHotend(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return target_temperature[HOTEND_INDEX];
|
||||
}
|
||||
|
||||
static int16_t degTargetBed() { return target_temperature_bed; }
|
||||
|
||||
#if WATCH_HOTENDS
|
||||
static void start_watching_heater(uint8_t e = 0);
|
||||
#endif
|
||||
|
||||
#if WATCH_THE_BED
|
||||
static void start_watching_bed();
|
||||
#endif
|
||||
|
||||
static void setTargetHotend(const int16_t celsius, uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
#ifdef MILLISECONDS_PREHEAT_TIME
|
||||
if (celsius == 0)
|
||||
reset_preheat_time(HOTEND_INDEX);
|
||||
else if (target_temperature[HOTEND_INDEX] == 0)
|
||||
start_preheat_time(HOTEND_INDEX);
|
||||
#endif
|
||||
target_temperature[HOTEND_INDEX] = celsius;
|
||||
#if WATCH_HOTENDS
|
||||
start_watching_heater(HOTEND_INDEX);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setTargetBed(const int16_t celsius) {
|
||||
#if HAS_HEATER_BED
|
||||
target_temperature_bed =
|
||||
#ifdef BED_MAXTEMP
|
||||
min(celsius, BED_MAXTEMP)
|
||||
#else
|
||||
celsius
|
||||
#endif
|
||||
;
|
||||
#if WATCH_THE_BED
|
||||
start_watching_bed();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isHeatingHotend(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return target_temperature[HOTEND_INDEX] > current_temperature[HOTEND_INDEX];
|
||||
}
|
||||
static bool isHeatingBed() { return target_temperature_bed > current_temperature_bed; }
|
||||
|
||||
static bool isCoolingHotend(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return target_temperature[HOTEND_INDEX] < current_temperature[HOTEND_INDEX];
|
||||
}
|
||||
static bool isCoolingBed() { return target_temperature_bed < current_temperature_bed; }
|
||||
|
||||
/**
|
||||
* The software PWM power for a heater
|
||||
*/
|
||||
static int getHeaterPower(int heater);
|
||||
|
||||
/**
|
||||
* Switch off all heaters, set all target temperatures to 0
|
||||
*/
|
||||
static void disable_all_heaters();
|
||||
|
||||
/**
|
||||
* Perform auto-tuning for hotend or bed in response to M303
|
||||
*/
|
||||
#if HAS_PID_HEATING
|
||||
static void PID_autotune(float temp, int hotend, int ncycles, bool set_result=false);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Update the temp manager when PID values change
|
||||
*/
|
||||
static void updatePID();
|
||||
|
||||
#if ENABLED(BABYSTEPPING)
|
||||
|
||||
static void babystep_axis(const AxisEnum axis, const int distance) {
|
||||
if (axis_known_position[axis]) {
|
||||
#if IS_CORE
|
||||
#if ENABLED(BABYSTEP_XY)
|
||||
switch (axis) {
|
||||
case CORE_AXIS_1: // X on CoreXY and CoreXZ, Y on CoreYZ
|
||||
babystepsTodo[CORE_AXIS_1] += distance * 2;
|
||||
babystepsTodo[CORE_AXIS_2] += distance * 2;
|
||||
break;
|
||||
case CORE_AXIS_2: // Y on CoreXY, Z on CoreXZ and CoreYZ
|
||||
babystepsTodo[CORE_AXIS_1] += CORESIGN(distance * 2);
|
||||
babystepsTodo[CORE_AXIS_2] -= CORESIGN(distance * 2);
|
||||
break;
|
||||
case NORMAL_AXIS: // Z on CoreXY, Y on CoreXZ, X on CoreYZ
|
||||
babystepsTodo[NORMAL_AXIS] += distance;
|
||||
break;
|
||||
}
|
||||
#elif CORE_IS_XZ || CORE_IS_YZ
|
||||
// Only Z stepping needs to be handled here
|
||||
babystepsTodo[CORE_AXIS_1] += CORESIGN(distance * 2);
|
||||
babystepsTodo[CORE_AXIS_2] -= CORESIGN(distance * 2);
|
||||
#else
|
||||
babystepsTodo[Z_AXIS] += distance;
|
||||
#endif
|
||||
#else
|
||||
babystepsTodo[axis] += distance;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BABYSTEPPING
|
||||
|
||||
#if ENABLED(PROBING_HEATERS_OFF)
|
||||
static void pause(const bool p);
|
||||
static bool is_paused() { return paused; }
|
||||
#endif
|
||||
|
||||
#if HEATER_IDLE_HANDLER
|
||||
static void start_heater_idle_timer(uint8_t e, millis_t timeout_ms) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
heater_idle_timeout_ms[HOTEND_INDEX] = millis() + timeout_ms;
|
||||
heater_idle_timeout_exceeded[HOTEND_INDEX] = false;
|
||||
}
|
||||
|
||||
static void reset_heater_idle_timer(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
heater_idle_timeout_ms[HOTEND_INDEX] = 0;
|
||||
heater_idle_timeout_exceeded[HOTEND_INDEX] = false;
|
||||
#if WATCH_HOTENDS
|
||||
start_watching_heater(HOTEND_INDEX);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_heater_idle(uint8_t e) {
|
||||
#if HOTENDS == 1
|
||||
UNUSED(e);
|
||||
#endif
|
||||
return heater_idle_timeout_exceeded[HOTEND_INDEX];
|
||||
}
|
||||
|
||||
#if HAS_TEMP_BED
|
||||
static void start_bed_idle_timer(millis_t timeout_ms) {
|
||||
bed_idle_timeout_ms = millis() + timeout_ms;
|
||||
bed_idle_timeout_exceeded = false;
|
||||
}
|
||||
|
||||
static void reset_bed_idle_timer() {
|
||||
bed_idle_timeout_ms = 0;
|
||||
bed_idle_timeout_exceeded = false;
|
||||
#if WATCH_THE_BED
|
||||
start_watching_bed();
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_bed_idle() {
|
||||
return bed_idle_timeout_exceeded;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
static void set_current_temp_raw();
|
||||
|
||||
static void updateTemperaturesFromRawValues();
|
||||
|
||||
#if ENABLED(HEATER_0_USES_MAX6675)
|
||||
static int read_max6675();
|
||||
#endif
|
||||
|
||||
static void checkExtruderAutoFans();
|
||||
|
||||
static float get_pid_output(const int8_t e);
|
||||
|
||||
#if ENABLED(PIDTEMPBED)
|
||||
static float get_pid_output_bed();
|
||||
#endif
|
||||
|
||||
static void _temp_error(const int8_t e, const char * const serial_msg, const char * const lcd_msg);
|
||||
static void min_temp_error(const int8_t e);
|
||||
static void max_temp_error(const int8_t e);
|
||||
|
||||
#if ENABLED(THERMAL_PROTECTION_HOTENDS) || HAS_THERMALLY_PROTECTED_BED
|
||||
|
||||
typedef enum TRState { TRInactive, TRFirstHeating, TRStable, TRRunaway } TRstate;
|
||||
|
||||
static void thermal_runaway_protection(TRState* state, millis_t* timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc);
|
||||
|
||||
#if ENABLED(THERMAL_PROTECTION_HOTENDS)
|
||||
static TRState thermal_runaway_state_machine[HOTENDS];
|
||||
static millis_t thermal_runaway_timer[HOTENDS];
|
||||
#endif
|
||||
|
||||
#if HAS_THERMALLY_PROTECTED_BED
|
||||
static TRState thermal_runaway_bed_state_machine;
|
||||
static millis_t thermal_runaway_bed_timer;
|
||||
#endif
|
||||
|
||||
#endif // THERMAL_PROTECTION
|
||||
|
||||
};
|
||||
|
||||
extern Temperature thermalManager;
|
||||
|
||||
#endif // TEMPERATURE_H
|
Reference in New Issue
Block a user