Move 'module' files

This commit is contained in:
Scott Lahteine
2017-09-06 06:28:30 -05:00
parent efa578d6b0
commit 0c9231fd04
17 changed files with 0 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View 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

View 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()

View 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

File diff suppressed because it is too large Load Diff

478
Marlin/src/module/planner.h Normal file
View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

401
Marlin/src/module/stepper.h Normal file
View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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