Bump to head with panner and ubl fixes

This commit is contained in:
InsanityAutomation
2018-07-08 16:48:40 -04:00
parent 5a4a107711
commit 1ab0d240b9
116 changed files with 3986 additions and 3016 deletions
+25 -17
View File
@@ -380,12 +380,6 @@
#define HAS_DEBUG_MENU (ENABLED(ULTIPANEL) && ENABLED(LCD_PROGRESS_BAR_TEST))
// MK2 Multiplexer forces SINGLENOZZLE and kills DISABLE_INACTIVE_EXTRUDER
#if ENABLED(MK2_MULTIPLEXER)
#define SINGLENOZZLE
#undef DISABLE_INACTIVE_EXTRUDER
#endif
/**
* Extruders have some combination of stepper motors and hotends
* so we separate these concepts into the defines:
@@ -396,25 +390,17 @@
* E_MANUAL - Number of E steppers for LCD move options
*
*/
#if ENABLED(SINGLENOZZLE) || ENABLED(MIXING_EXTRUDER) // One hotend, one thermistor, no XY offset
#define HOTENDS 1
#undef TEMP_SENSOR_1_AS_REDUNDANT
#undef HOTEND_OFFSET_X
#undef HOTEND_OFFSET_Y
#else // Two hotends
#define HOTENDS EXTRUDERS
#endif
#if ENABLED(SWITCHING_EXTRUDER) // One stepper for every two EXTRUDERS
#if EXTRUDERS > 4
#define E_STEPPERS 3
#define E_MANUAL 3
#elif EXTRUDERS > 2
#define E_STEPPERS 2
#define E_MANUAL 2
#else
#define E_STEPPERS 1
#endif
#if DISABLED(SWITCHING_NOZZLE)
#define HOTENDS E_STEPPERS
#endif
#define E_MANUAL EXTRUDERS
#elif ENABLED(MIXING_EXTRUDER)
#define E_STEPPERS MIXING_STEPPERS
@@ -424,6 +410,28 @@
#define E_MANUAL EXTRUDERS
#endif
// No inactive extruders with MK2_MULTIPLEXER or SWITCHING_NOZZLE
#if ENABLED(MK2_MULTIPLEXER) || ENABLED(SWITCHING_NOZZLE)
#undef DISABLE_INACTIVE_EXTRUDER
#endif
// MK2 Multiplexer forces SINGLENOZZLE
#if ENABLED(MK2_MULTIPLEXER)
#define SINGLENOZZLE
#endif
#if ENABLED(SINGLENOZZLE) || ENABLED(MIXING_EXTRUDER) // One hotend, one thermistor, no XY offset
#undef HOTENDS
#define HOTENDS 1
#undef TEMP_SENSOR_1_AS_REDUNDANT
#undef HOTEND_OFFSET_X
#undef HOTEND_OFFSET_Y
#endif
#ifndef HOTENDS
#define HOTENDS EXTRUDERS
#endif
#define DO_SWITCH_EXTRUDER (ENABLED(SWITCHING_EXTRUDER) && (DISABLED(SWITCHING_NOZZLE) || SWITCHING_EXTRUDER_SERVO_NR != SWITCHING_NOZZLE_SERVO_NR))
/**
+6 -14
View File
@@ -205,15 +205,6 @@
#define MAX_AUTORETRACT 99
#endif
/**
* MAX_STEP_FREQUENCY differs for TOSHIBA
*/
#if ENABLED(CONFIG_STEPPERS_TOSHIBA)
#define MAX_STEP_FREQUENCY 10000 // Max step frequency for Toshiba Stepper Controllers
#else
#define MAX_STEP_FREQUENCY 40000 // Max step frequency for Ultimaker (5000 pps / half step)
#endif
// MS1 MS2 Stepper Driver Microstepping mode table
#define MICROSTEP1 LOW,LOW
#if ENABLED(HEROIC_STEPPER_DRIVERS)
@@ -616,24 +607,27 @@
#define HAS_X2_ENABLE (PIN_EXISTS(X2_ENABLE))
#define HAS_X2_DIR (PIN_EXISTS(X2_DIR))
#define HAS_X2_STEP (PIN_EXISTS(X2_STEP))
#define HAS_Y_MICROSTEPS (PIN_EXISTS(Y_MS1))
#define HAS_X2_MICROSTEPS (PIN_EXISTS(X2_MS1))
#define HAS_Y_ENABLE (PIN_EXISTS(Y_ENABLE))
#define HAS_Y_DIR (PIN_EXISTS(Y_DIR))
#define HAS_Y_STEP (PIN_EXISTS(Y_STEP))
#define HAS_Z_MICROSTEPS (PIN_EXISTS(Z_MS1))
#define HAS_Y_MICROSTEPS (PIN_EXISTS(Y_MS1))
#define HAS_Y2_ENABLE (PIN_EXISTS(Y2_ENABLE))
#define HAS_Y2_DIR (PIN_EXISTS(Y2_DIR))
#define HAS_Y2_STEP (PIN_EXISTS(Y2_STEP))
#define HAS_Y2_MICROSTEPS (PIN_EXISTS(Y2_MS1))
#define HAS_Z_ENABLE (PIN_EXISTS(Z_ENABLE))
#define HAS_Z_DIR (PIN_EXISTS(Z_DIR))
#define HAS_Z_STEP (PIN_EXISTS(Z_STEP))
#define HAS_Z_MICROSTEPS (PIN_EXISTS(Z_MS1))
#define HAS_Z2_ENABLE (PIN_EXISTS(Z2_ENABLE))
#define HAS_Z2_DIR (PIN_EXISTS(Z2_DIR))
#define HAS_Z2_STEP (PIN_EXISTS(Z2_STEP))
#define HAS_Z2_MICROSTEPS (PIN_EXISTS(Z2_MS1))
// Extruder steppers and solenoids
#define HAS_E0_ENABLE (PIN_EXISTS(E0_ENABLE))
@@ -984,6 +978,7 @@
#define PLANNER_LEVELING (OLDSCHOOL_ABL || ENABLED(MESH_BED_LEVELING) || UBL_SEGMENTED || ENABLED(SKEW_CORRECTION))
#define HAS_PROBING_PROCEDURE (HAS_ABL || ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST))
#define HAS_UBL_AND_CURVES (ENABLED(AUTO_BED_LEVELING_UBL) && !PLANNER_LEVELING && (ENABLED(ARC_SUPPORT) || ENABLED(BEZIER_CURVE_SUPPORT)))
#define HAS_FEEDRATE_SCALING (ENABLED(SCARA_FEEDRATE_SCALING) || ENABLED(DELTA_FEEDRATE_SCALING))
#if ENABLED(AUTO_BED_LEVELING_UBL)
#undef LCD_BED_LEVELING
@@ -1247,9 +1242,6 @@
#define MANUAL_PROBE_HEIGHT Z_HOMING_HEIGHT
#endif
// Stepper pulse duration, in cycles
#define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND)
// Updated G92 behavior shifts the workspace
#define HAS_POSITION_SHIFT DISABLED(NO_WORKSPACE_OFFSETS)
// The home offset also shifts the coordinate space
+1 -1
View File
@@ -722,7 +722,7 @@
#if ENABLED(BABYSTEPPING)
//#define BABYSTEP_XY // Also enable X/Y Babystepping. Not supported on DELTA!
#define BABYSTEP_INVERT_Z false // Change if Z babysteps should go the other way
#define BABYSTEP_MULTIPLICATOR 1 // Babysteps are very small. Increase for faster motion.
#define BABYSTEP_MULTIPLICATOR 25 // Babysteps are very small. Increase for faster motion.
#define BABYSTEP_ZPROBE_OFFSET // Enable to combine M851 and Babystepping
#define DOUBLECLICK_FOR_Z_BABYSTEPPING // Double-click on the Status Screen for Z Babystepping.
#define DOUBLECLICK_MAX_INTERVAL 1250 // Maximum interval between clicks, in milliseconds.
+50 -17
View File
@@ -48,10 +48,14 @@
// Bracket code that shouldn't be interrupted
#ifndef CRITICAL_SECTION_START
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
#define CRITICAL_SECTION_END SREG = _sreg;
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END SREG = _sreg
#endif
#define ISRS_ENABLED() TEST(SREG, SREG_I)
#define ENABLE_ISRS() sei()
#define DISABLE_ISRS() cli()
// --------------------------------------------------------------------------
// Types
// --------------------------------------------------------------------------
@@ -89,22 +93,17 @@ inline uint8_t HAL_get_reset_source(void) { return MCUSR; }
#define STEP_TIMER_NUM 1
#define TEMP_TIMER_NUM 0
#define PULSE_TIMER_NUM TEMP_TIMER_NUM
#define HAL_STEPPER_TIMER_RATE HAL_TIMER_RATE
#define HAL_TICKS_PER_US ((HAL_STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double
#define STEPPER_TIMER_PRESCALE 8
#define STEP_TIMER_MIN_INTERVAL 8 // minimum time in µs between stepper interrupts
#define PULSE_TIMER_NUM STEP_TIMER_NUM
#define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0)
#define TIMER_OCR_1 OCR1A
#define TIMER_COUNTER_1 TCNT1
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
#define STEPPER_TIMER_PRESCALE 8
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double
#define TIMER_OCR_0 OCR0A
#define TIMER_COUNTER_0 TCNT0
#define PULSE_TIMER_PRESCALE 8
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
@@ -114,7 +113,42 @@ inline uint8_t HAL_get_reset_source(void) { return MCUSR; }
#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0B)
#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0B)
#define HAL_timer_start(timer_num, frequency)
FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
UNUSED(frequency);
switch (timer_num) {
case STEP_TIMER_NUM:
// waveform generation = 0100 = CTC
SET_WGM(1, CTC_OCRnA);
// output mode = 00 (disconnected)
SET_COMA(1, NORMAL);
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
SET_CS(1, PRESCALER_8); // CS 2 = 1/8 prescaler
// Init Stepper ISR to 122 Hz for quick starting
// (F_CPU) / (STEPPER_TIMER_PRESCALE) / frequency
OCR1A = 0x4000;
TCNT1 = 0;
break;
case TEMP_TIMER_NUM:
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0B = 128;
break;
}
}
#define TIMER_OCR_1 OCR1A
#define TIMER_COUNTER_1 TCNT1
#define TIMER_OCR_0 OCR0A
#define TIMER_COUNTER_0 TCNT0
#define _CAT(a, ...) a ## __VA_ARGS__
#define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
@@ -148,7 +182,6 @@ void TIMER1_COMPA_vect (void) { \
A("lds r16, %[timsk1]") /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
A("andi r16,~%[msk1]") /* 1 Disable the stepper ISR */ \
A("sts %[timsk1], r16") /* 2 And set the new value */ \
A("sei") /* 1 Enable global interrupts - stepper and temperature ISRs are disabled, so no risk of reentry or being preempted by the temperature ISR */ \
A("push r16") /* 2 Save TIMSK1 into stack */ \
A("in r16, 0x3B") /* 1 Get RAMPZ register */ \
A("push r16") /* 2 Save RAMPZ into stack */ \
@@ -258,7 +291,7 @@ void TIMER0_COMPB_vect (void) { \
A("out 0x3B, r16") /* 1 Restore RAMPZ register to its original value */ \
A("pop r16") /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
A("ori r16,%[msk0]") /* 1 Enable temperature ISR */ \
A("cli") /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don´t want to reenter this handler until the current one is done */ \
A("cli") /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don't want to reenter this handler until the current one is done */ \
A("sts %[timsk0], r16") /* 2 And restore the old value */ \
A("pop r16") /* 2 Get the old SREG */ \
A("out __SREG__, r16") /* 1 And restore the SREG value */ \
+1 -1
View File
@@ -181,7 +181,7 @@
if (errPrstIdx >= I2CPE_ERR_PRST_ARRAY_SIZE) {
float sumP = 0;
LOOP_L_N(i, I2CPE_ERR_PRST_ARRAY_SIZE) sumP += errPrst[i];
const int32_t errorP = int32_t(sumP * (1.0 / (I2CPE_ERR_PRST_ARRAY_SIZE)));
const int32_t errorP = int32_t(sumP * (1.0f / (I2CPE_ERR_PRST_ARRAY_SIZE)));
SERIAL_ECHO(axis_codes[encoderAxis]);
SERIAL_ECHOPAIR(" - err detected: ", errorP * planner.steps_to_mm[encoderAxis]);
SERIAL_ECHOLNPGM("mm; correcting!");
-4
View File
@@ -134,16 +134,12 @@
nextErrorCountTime = 0,
lastErrorTime;
//double positionMm; //calculate
#if ENABLED(I2CPE_ERR_ROLLING_AVERAGE)
uint8_t errIdx = 0, errPrstIdx = 0;
int err[I2CPE_ERR_ARRAY_SIZE] = { 0 },
errPrst[I2CPE_ERR_PRST_ARRAY_SIZE] = { 0 };
#endif
//float positionMm; //calculate
public:
void init(const uint8_t address, const AxisEnum axis);
void reset();
+25 -32
View File
@@ -60,10 +60,10 @@ extern const char axis_codes[XYZE];
#if HAS_X2_ENABLE
#define enable_X() do{ X_ENABLE_WRITE( X_ENABLE_ON); X2_ENABLE_WRITE( X_ENABLE_ON); }while(0)
#define disable_X() do{ X_ENABLE_WRITE(!X_ENABLE_ON); X2_ENABLE_WRITE(!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }while(0)
#define disable_X() do{ X_ENABLE_WRITE(!X_ENABLE_ON); X2_ENABLE_WRITE(!X_ENABLE_ON); CBI(axis_known_position, X_AXIS); }while(0)
#elif HAS_X_ENABLE
#define enable_X() X_ENABLE_WRITE( X_ENABLE_ON)
#define disable_X() do{ X_ENABLE_WRITE(!X_ENABLE_ON); axis_known_position[X_AXIS] = false; }while(0)
#define disable_X() do{ X_ENABLE_WRITE(!X_ENABLE_ON); CBI(axis_known_position, X_AXIS); }while(0)
#else
#define enable_X() NOOP
#define disable_X() NOOP
@@ -71,10 +71,10 @@ extern const char axis_codes[XYZE];
#if HAS_Y2_ENABLE
#define enable_Y() do{ Y_ENABLE_WRITE( Y_ENABLE_ON); Y2_ENABLE_WRITE(Y_ENABLE_ON); }while(0)
#define disable_Y() do{ Y_ENABLE_WRITE(!Y_ENABLE_ON); Y2_ENABLE_WRITE(!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }while(0)
#define disable_Y() do{ Y_ENABLE_WRITE(!Y_ENABLE_ON); Y2_ENABLE_WRITE(!Y_ENABLE_ON); CBI(axis_known_position, Y_AXIS); }while(0)
#elif HAS_Y_ENABLE
#define enable_Y() Y_ENABLE_WRITE( Y_ENABLE_ON)
#define disable_Y() do{ Y_ENABLE_WRITE(!Y_ENABLE_ON); axis_known_position[Y_AXIS] = false; }while(0)
#define disable_Y() do{ Y_ENABLE_WRITE(!Y_ENABLE_ON); CBI(axis_known_position, Y_AXIS); }while(0)
#else
#define enable_Y() NOOP
#define disable_Y() NOOP
@@ -82,10 +82,10 @@ extern const char axis_codes[XYZE];
#if HAS_Z2_ENABLE
#define enable_Z() do{ Z_ENABLE_WRITE( Z_ENABLE_ON); Z2_ENABLE_WRITE(Z_ENABLE_ON); }while(0)
#define disable_Z() do{ Z_ENABLE_WRITE(!Z_ENABLE_ON); Z2_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }while(0)
#define disable_Z() do{ Z_ENABLE_WRITE(!Z_ENABLE_ON); Z2_ENABLE_WRITE(!Z_ENABLE_ON); CBI(axis_known_position, Z_AXIS); }while(0)
#elif HAS_Z_ENABLE
#define enable_Z() Z_ENABLE_WRITE( Z_ENABLE_ON)
#define disable_Z() do{ Z_ENABLE_WRITE(!Z_ENABLE_ON); axis_known_position[Z_AXIS] = false; }while(0)
#define disable_Z() do{ Z_ENABLE_WRITE(!Z_ENABLE_ON); CBI(axis_known_position, Z_AXIS); }while(0)
#else
#define enable_Z() NOOP
#define disable_Z() NOOP
@@ -220,11 +220,16 @@ inline void reset_stepper_timeout() { previous_move_ms = millis(); }
extern float feedrate_mm_s;
extern int16_t feedrate_percentage;
#define MMS_SCALED(MM_S) ((MM_S)*feedrate_percentage*0.01)
#define MMS_SCALED(MM_S) ((MM_S)*feedrate_percentage*0.01f)
extern bool axis_relative_modes[XYZE];
extern uint8_t axis_homed, axis_known_position;
constexpr uint8_t xyz_bits = _BV(X_AXIS) | _BV(Y_AXIS) | _BV(Z_AXIS);
FORCE_INLINE bool all_axes_homed() { return (axis_homed & xyz_bits) == xyz_bits; }
FORCE_INLINE bool all_axes_known() { return (axis_known_position & xyz_bits) == xyz_bits; }
extern bool axis_relative_modes[];
extern bool axis_known_position[XYZ];
extern bool axis_homed[XYZ];
extern volatile bool wait_for_heatup;
#if HAS_RESUME_CONTINUE
@@ -316,22 +321,15 @@ void report_current_position();
void recalc_delta_settings();
float delta_safe_distance_from_top();
#if ENABLED(DELTA_FAST_SQRT)
float Q_rsqrt(const float number);
#define _SQRT(n) (1.0f / Q_rsqrt(n))
#else
#define _SQRT(n) SQRT(n)
#endif
// Macro to obtain the Z position of an individual tower
#define DELTA_Z(V,T) V[Z_AXIS] + _SQRT( \
#define DELTA_Z(V,T) V[Z_AXIS] + SQRT( \
delta_diagonal_rod_2_tower[T] - HYPOT2( \
delta_tower[T][X_AXIS] - V[X_AXIS], \
delta_tower[T][Y_AXIS] - V[Y_AXIS] \
) \
)
#define DELTA_IK(V) do { \
#define DELTA_IK(V) do { \
delta[A_AXIS] = DELTA_Z(V, A_AXIS); \
delta[B_AXIS] = DELTA_Z(V, B_AXIS); \
delta[C_AXIS] = DELTA_Z(V, C_AXIS); \
@@ -370,11 +368,6 @@ void report_current_position();
void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const element_2d_fn fn);
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
typedef struct { double A, B, D; } linear_fit;
linear_fit* lsf_linear_fit(double x[], double y[], double z[], const int);
#endif
#if HAS_LEVELING
bool leveling_is_valid();
void set_bed_leveling_enabled(const bool enable=true);
@@ -468,10 +461,10 @@ void prepare_move_to_destination();
/**
* Blocking movement and shorthand functions
*/
void do_blocking_move_to(const float rx, const float ry, const float rz, const float &fr_mm_s=0.0);
void do_blocking_move_to_x(const float &rx, const float &fr_mm_s=0.0);
void do_blocking_move_to_z(const float &rz, const float &fr_mm_s=0.0);
void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm_s=0.0);
void do_blocking_move_to(const float rx, const float ry, const float rz, const float &fr_mm_s=0);
void do_blocking_move_to_x(const float &rx, const float &fr_mm_s=0);
void do_blocking_move_to_z(const float &rz, const float &fr_mm_s=0);
void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm_s=0);
#if ENABLED(ARC_SUPPORT)
void plan_arc(const float(&cart)[XYZE], const float(&offset)[2], const bool clockwise);
@@ -531,8 +524,8 @@ void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm
// Return true if the given position is within the machine bounds.
inline bool position_is_reachable(const float &rx, const float &ry) {
// Add 0.001 margin to deal with float imprecision
return WITHIN(rx, X_MIN_POS - 0.001, X_MAX_POS + 0.001)
&& WITHIN(ry, Y_MIN_POS - 0.001, Y_MAX_POS + 0.001);
return WITHIN(rx, X_MIN_POS - 0.001f, X_MAX_POS + 0.001f)
&& WITHIN(ry, Y_MIN_POS - 0.001f, Y_MAX_POS + 0.001f);
}
#if HAS_BED_PROBE
@@ -545,8 +538,8 @@ void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm
*/
inline bool position_is_reachable_by_probe(const float &rx, const float &ry) {
return position_is_reachable(rx - (X_PROBE_OFFSET_FROM_EXTRUDER), ry - (Y_PROBE_OFFSET_FROM_EXTRUDER))
&& WITHIN(rx, MIN_PROBE_X - 0.001, MAX_PROBE_X + 0.001)
&& WITHIN(ry, MIN_PROBE_Y - 0.001, MAX_PROBE_Y + 0.001);
&& WITHIN(rx, MIN_PROBE_X - 0.001f, MAX_PROBE_X + 0.001f)
&& WITHIN(ry, MIN_PROBE_Y - 0.001f, MAX_PROBE_Y + 0.001f);
}
#endif
+380 -209
View File
@@ -28,6 +28,7 @@
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
* Modified 10 June 2018 by Eduardo José Tagle (See #10991)
*/
// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)
@@ -55,140 +56,312 @@
ring_buffer_r rx_buffer = { { 0 }, 0, 0 };
#if TX_BUFFER_SIZE > 0
ring_buffer_t tx_buffer = { { 0 }, 0, 0 };
static bool _written;
#endif
static bool _written;
#endif
#if ENABLED(SERIAL_XON_XOFF)
constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80; // XON / XOFF Character was sent
constexpr uint8_t XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent
XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
// XON / XOFF character definitions
constexpr uint8_t XON_CHAR = 17;
constexpr uint8_t XOFF_CHAR = 19;
constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19;
uint8_t xon_xoff_state = XON_XOFF_CHAR_SENT | XON_CHAR;
#endif
void clear_command_queue();
#if ENABLED(SERIAL_STATS_DROPPED_RX)
uint8_t rx_dropped_bytes = 0;
#endif
#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
uint8_t rx_buffer_overruns = 0;
#endif
#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
uint8_t rx_framing_errors = 0;
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
ring_buffer_pos_t rx_max_enqueued = 0;
#endif
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
#if ENABLED(EMERGENCY_PARSER)
#include "emergency_parser.h"
#endif
// "Atomically" read the RX head index value without disabling interrupts:
// This MUST be called with RX interrupts enabled, and CAN'T be called
// from the RX ISR itself!
FORCE_INLINE ring_buffer_pos_t atomic_read_rx_head() {
#if RX_BUFFER_SIZE > 256
// Keep reading until 2 consecutive reads return the same value,
// meaning there was no update in-between caused by an interrupt.
// This works because serial RX interrupts happen at a slower rate
// than successive reads of a variable, so 2 consecutive reads with
// the same value means no interrupt updated it.
ring_buffer_pos_t vold, vnew = rx_buffer.head;
sw_barrier();
do {
vold = vnew;
vnew = rx_buffer.head;
sw_barrier();
} while (vold != vnew);
return vnew;
#else
// With an 8bit index, reads are always atomic. No need for special handling
return rx_buffer.head;
#endif
}
#if RX_BUFFER_SIZE > 256
static volatile bool rx_tail_value_not_stable = false;
static volatile uint16_t rx_tail_value_backup = 0;
#endif
// Set RX tail index, taking into account the RX ISR could interrupt
// the write to this variable in the middle - So a backup strategy
// is used to ensure reads of the correct values.
// -Must NOT be called from the RX ISR -
FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value) {
#if RX_BUFFER_SIZE > 256
// Store the new value in the backup
rx_tail_value_backup = value;
sw_barrier();
// Flag we are about to change the true value
rx_tail_value_not_stable = true;
sw_barrier();
// Store the new value
rx_buffer.tail = value;
sw_barrier();
// Signal the new value is completely stored into the value
rx_tail_value_not_stable = false;
sw_barrier();
#else
rx_buffer.tail = value;
#endif
}
// Get the RX tail index, taking into account the read could be
// interrupting in the middle of the update of that index value
// -Called from the RX ISR -
FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail() {
#if RX_BUFFER_SIZE > 256
// If the true index is being modified, return the backup value
if (rx_tail_value_not_stable) return rx_tail_value_backup;
#endif
// The true index is stable, return it
return rx_buffer.tail;
}
// (called with RX interrupts disabled)
FORCE_INLINE void store_rxd_char() {
const ring_buffer_pos_t h = rx_buffer.head,
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Get the tail - Nothing can alter its value while this ISR is executing, but there's
// a chance that this ISR interrupted the main process while it was updating the index.
// The backup mechanism ensures the correct value is always returned.
const ring_buffer_pos_t t = atomic_read_rx_tail();
// Get the head pointer - This ISR is the only one that modifies its value, so it's safe to read here
ring_buffer_pos_t h = rx_buffer.head;
// Get the next element
ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// This must read the M_UCSRxA register before reading the received byte to detect error causes
#if ENABLED(SERIAL_STATS_DROPPED_RX)
if (TEST(M_UCSRxA, M_DORx) && !++rx_dropped_bytes) --rx_dropped_bytes;
#endif
#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
if (TEST(M_UCSRxA, M_DORx) && !++rx_buffer_overruns) --rx_buffer_overruns;
#endif
#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
if (TEST(M_UCSRxA, M_FEx) && !++rx_framing_errors) --rx_framing_errors;
#endif
// Read the character from the USART
uint8_t c = M_UDRx;
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(c);
#endif
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the buffer is
// critical, so don't write the character or advance the head.
const char c = M_UDRx;
if (i != rx_buffer.tail) {
// (such that the head would advance to the current tail), the RX FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
rx_buffer.head = i;
}
else {
#if ENABLED(SERIAL_STATS_DROPPED_RX)
if (!++rx_dropped_bytes) ++rx_dropped_bytes;
#endif
h = i;
}
#if ENABLED(SERIAL_STATS_DROPPED_RX)
else if (!++rx_dropped_bytes) --rx_dropped_bytes;
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
// calculate count of bytes stored into the RX buffer
ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Calculate count of bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Keep track of the maximum count of enqueued bytes
NOLESS(rx_max_enqueued, rx_count);
#endif
#if ENABLED(SERIAL_XON_XOFF)
// for high speed transfers, we can use XON/XOFF protocol to do
// software handshake and avoid overruns.
// If the last char that was sent was an XON
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
// calculate count of bytes stored into the RX buffer
ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// if we are above 12.5% of RX buffer capacity, send XOFF before
// we run out of RX buffer space .. We need 325 bytes @ 250kbits/s to
// let the host react and stop sending bytes. This translates to 13mS
// propagation time.
// If over 12.5% of RX buffer capacity, send XOFF before running out of
// RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
// and stop sending bytes. This translates to 13mS propagation time.
if (rx_count >= (RX_BUFFER_SIZE) / 8) {
// If TX interrupts are disabled and data register is empty,
// just write the byte to the data register and be done. This
// shortcut helps significantly improve the effective datarate
// at high (>500kbit/s) bitrates, where interrupt overhead
// becomes a slowdown.
if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
// Send an XOFF character
M_UDRx = XOFF_CHAR;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
SBI(M_UCSRxA, M_TXCx);
// And remember it was sent
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted.
// Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
// to be in the middle of trying to disable the RX interrupt in the main program, eventually the
// enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
// the sending of the XOFF char is to send it HERE AND NOW.
// About to send the XOFF char
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// Wait until the TX register becomes empty and send it - Here there could be a problem
// - While waiting for the TX register to empty, the RX register could receive a new
// character. This must also handle that situation!
while (!TEST(M_UCSRxA, M_UDREx)) {
if (TEST(M_UCSRxA,M_RXCx)) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Read the character from the USART
c = M_UDRx;
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(c);
#endif
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
#if ENABLED(SERIAL_STATS_DROPPED_RX)
else if (!++rx_dropped_bytes) --rx_dropped_bytes;
#endif
}
sw_barrier();
}
else {
// TX interrupts disabled, but buffer still not empty ... or
// TX interrupts enabled. Reenable TX ints and schedule XOFF
// character to be sent
#if TX_BUFFER_SIZE > 0
SBI(M_UCSRxB, M_UDRIEx);
xon_xoff_state = XOFF_CHAR;
#else
// We are not using TX interrupts, we will have to send this manually
while (!TEST(M_UCSRxA, M_UDREx)) {/* nada */}
M_UDRx = XOFF_CHAR;
// And remember we already sent it
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
#endif
M_UDRx = XOFF_CHAR;
// Clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
SBI(M_UCSRxA, M_TXCx);
// At this point there could be a race condition between the write() function
// and this sending of the XOFF char. This interrupt could happen between the
// wait to be empty TX buffer loop and the actual write of the character. Since
// the TX buffer is full because it's sending the XOFF char, the only way to be
// sure the write() function will succeed is to wait for the XOFF char to be
// completely sent. Since an extra character could be received during the wait
// it must also be handled!
while (!TEST(M_UCSRxA, M_UDREx)) {
if (TEST(M_UCSRxA,M_RXCx)) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// Read the character from the USART
c = M_UDRx;
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(c);
#endif
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
#if ENABLED(SERIAL_STATS_DROPPED_RX)
else if (!++rx_dropped_bytes) --rx_dropped_bytes;
#endif
}
sw_barrier();
}
// At this point everything is ready. The write() function won't
// have any issues writing to the UART TX register if it needs to!
}
}
#endif // SERIAL_XON_XOFF
#if ENABLED(EMERGENCY_PARSER)
emergency_parser.update(c);
#endif
// Store the new head value - The main loop will retry until the value is stable
rx_buffer.head = h;
}
#if TX_BUFFER_SIZE > 0
// (called with TX irqs disabled)
FORCE_INLINE void _tx_udr_empty_irq(void) {
// If interrupts are enabled, there must be more data in the output
// buffer.
// Read positions
uint8_t t = tx_buffer.tail;
const uint8_t h = tx_buffer.head;
#if ENABLED(SERIAL_XON_XOFF)
// Do a priority insertion of an XON/XOFF char, if needed.
const uint8_t state = xon_xoff_state;
if (!(state & XON_XOFF_CHAR_SENT)) {
M_UDRx = state & XON_XOFF_CHAR_MASK;
xon_xoff_state = state | XON_XOFF_CHAR_SENT;
// If an XON char is pending to be sent, do it now
if (xon_xoff_state == XON_CHAR) {
// Send the character
M_UDRx = XON_CHAR;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
SBI(M_UCSRxA, M_TXCx);
// Remember we sent it.
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
// If nothing else to transmit, just disable TX interrupts.
if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
else
#endif
{ // Send the next byte
const uint8_t t = tx_buffer.tail, c = tx_buffer.buffer[t];
tx_buffer.tail = (t + 1) & (TX_BUFFER_SIZE - 1);
M_UDRx = c;
// If nothing to transmit, just disable TX interrupts. This could
// happen as the result of the non atomicity of the disabling of RX
// interrupts that could end reenabling TX interrupts as a side effect.
if (h == t) {
CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
// There is something to TX, Send the next byte
const uint8_t c = tx_buffer.buffer[t];
t = (t + 1) & (TX_BUFFER_SIZE - 1);
M_UDRx = c;
tx_buffer.tail = t;
// Clear the TXC bit (by writing a one to its bit location).
// Ensures flush() won't return until the bytes are actually written/
SBI(M_UCSRxA, M_TXCx);
// Disable interrupts if the buffer is empty
if (tx_buffer.head == tx_buffer.tail)
CBI(M_UCSRxB, M_UDRIEx);
// Disable interrupts if there is nothing to transmit following this byte
if (h == t) CBI(M_UCSRxB, M_UDRIEx); // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
}
#ifdef M_USARTx_UDRE_vect
@@ -232,8 +405,8 @@
SBI(M_UCSRxB, M_RXCIEx);
#if TX_BUFFER_SIZE > 0
CBI(M_UCSRxB, M_UDRIEx);
_written = false;
#endif
_written = false;
}
void MarlinSerial::end() {
@@ -243,177 +416,179 @@
CBI(M_UCSRxB, M_UDRIEx);
}
void MarlinSerial::checkRx(void) {
if (TEST(M_UCSRxA, M_RXCx)) {
CRITICAL_SECTION_START;
store_rxd_char();
CRITICAL_SECTION_END;
}
}
int MarlinSerial::peek(void) {
CRITICAL_SECTION_START;
const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
CRITICAL_SECTION_END;
return v;
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return h == t ? -1 : rx_buffer.buffer[t];
}
int MarlinSerial::read(void) {
int v;
CRITICAL_SECTION_START;
const ring_buffer_pos_t t = rx_buffer.tail;
if (rx_buffer.head == t)
v = -1;
else {
v = rx_buffer.buffer[t];
rx_buffer.tail = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
const ring_buffer_pos_t h = atomic_read_rx_head();
#if ENABLED(SERIAL_XON_XOFF)
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(rx_buffer.head - rx_buffer.tail) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
// When below 10% of RX buffer capacity, send XON before
// running out of RX buffer bytes
if (rx_count < (RX_BUFFER_SIZE) / 10) {
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
CRITICAL_SECTION_END; // End critical section before returning!
writeNoHandshake(XON_CHAR);
return v;
}
}
#endif
// Read the tail. Main thread owns it, so it is safe to directly read it
ring_buffer_pos_t t = rx_buffer.tail;
// If nothing to read, return now
if (h == t) return -1;
// Get the next char
const int v = rx_buffer.buffer[t];
t = (ring_buffer_pos_t)(t + 1) & (RX_BUFFER_SIZE - 1);
// Advance tail - Making sure the RX ISR will always get an stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(t);
#if ENABLED(SERIAL_XON_XOFF)
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(RX_BUFFER_SIZE - 1);
if (rx_count < (RX_BUFFER_SIZE) / 10) {
#if TX_BUFFER_SIZE > 0
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable them
SBI(M_UCSRxB, M_UDRIEx);
#else
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
M_UDRx = XON_CHAR;
#endif
}
}
CRITICAL_SECTION_END;
#endif
return v;
}
ring_buffer_pos_t MarlinSerial::available(void) {
CRITICAL_SECTION_START;
const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
CRITICAL_SECTION_END;
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return (ring_buffer_pos_t)(RX_BUFFER_SIZE + h - t) & (RX_BUFFER_SIZE - 1);
}
void MarlinSerial::flush(void) {
// Don't change this order of operations. If the RX interrupt occurs between
// reading rx_buffer_head and updating rx_buffer_tail, the previous rx_buffer_head
// may be written to rx_buffer_tail, making the buffer appear full rather than empty.
CRITICAL_SECTION_START;
rx_buffer.head = rx_buffer.tail = 0;
clear_command_queue();
CRITICAL_SECTION_END;
// Set the tail to the head:
// - Read the RX head index in a safe way. (See atomic_read_rx_head.)
// - Set the tail, making sure the RX ISR will always get a stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(atomic_read_rx_head());
#if ENABLED(SERIAL_XON_XOFF)
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
writeNoHandshake(XON_CHAR);
#if TX_BUFFER_SIZE > 0
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable it.
SBI(M_UCSRxB, M_UDRIEx);
#else
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
M_UDRx = XON_CHAR;
#endif
}
#endif
}
#if TX_BUFFER_SIZE > 0
uint8_t MarlinSerial::availableForWrite(void) {
CRITICAL_SECTION_START;
const uint8_t h = tx_buffer.head, t = tx_buffer.tail;
CRITICAL_SECTION_END;
return (uint8_t)(TX_BUFFER_SIZE + h - t) & (TX_BUFFER_SIZE - 1);
}
void MarlinSerial::write(const uint8_t c) {
#if ENABLED(SERIAL_XON_XOFF)
const uint8_t state = xon_xoff_state;
if (!(state & XON_XOFF_CHAR_SENT)) {
// Send 2 chars: XON/XOFF, then a user-specified char
writeNoHandshake(state & XON_XOFF_CHAR_MASK);
xon_xoff_state = state | XON_XOFF_CHAR_SENT;
}
#endif
writeNoHandshake(c);
}
void MarlinSerial::writeNoHandshake(const uint8_t c) {
_written = true;
CRITICAL_SECTION_START;
bool emty = (tx_buffer.head == tx_buffer.tail);
CRITICAL_SECTION_END;
// If the buffer and the data register is empty, just write the byte
// to the data register and be done. This shortcut helps
// significantly improve the effective datarate at high (>
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
if (emty && TEST(M_UCSRxA, M_UDREx)) {
CRITICAL_SECTION_START;
M_UDRx = c;
SBI(M_UCSRxA, M_TXCx);
CRITICAL_SECTION_END;
// If the TX interrupts are disabled and the data register
// is empty, just write the byte to the data register and
// be done. This shortcut helps significantly improve the
// effective datarate at high (>500kbit/s) bitrates, where
// interrupt overhead becomes a slowdown.
// Yes, there is a race condition between the sending of the
// XOFF char at the RX ISR, but it is properly handled there
if (!TEST(M_UCSRxB, M_UDRIEx) && TEST(M_UCSRxA, M_UDREx)) {
M_UDRx = c;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
SBI(M_UCSRxA, M_TXCx);
return;
}
const uint8_t i = (tx_buffer.head + 1) & (TX_BUFFER_SIZE - 1);
// If the output buffer is full, there's nothing for it other than to
// wait for the interrupt handler to empty it a bit
while (i == tx_buffer.tail) {
if (!TEST(SREG, SREG_I)) {
// Interrupts are disabled, so we'll have to poll the data
// register empty flag ourselves. If it is set, pretend an
// interrupt has happened and call the handler to free up
// space for us.
if (TEST(M_UCSRxA, M_UDREx))
_tx_udr_empty_irq();
}
else {
// nop, the interrupt handler will free up space for us
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) {
// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
// If we can transmit another byte, do it.
if (TEST(M_UCSRxA, M_UDREx)) _tx_udr_empty_irq();
// Make sure compiler rereads tx_buffer.tail
sw_barrier();
}
}
else {
// Interrupts are enabled, just wait until there is space
while (i == tx_buffer.tail) { sw_barrier(); }
}
// Store new char. head is always safe to move
tx_buffer.buffer[tx_buffer.head] = c;
{ CRITICAL_SECTION_START;
tx_buffer.head = i;
SBI(M_UCSRxB, M_UDRIEx);
CRITICAL_SECTION_END;
}
return;
tx_buffer.head = i;
// Enable TX ISR - Non atomic, but it will eventually enable TX ISR
SBI(M_UCSRxB, M_UDRIEx);
}
void MarlinSerial::flushTX(void) {
// TX
// If we have never written a byte, no need to flush. This special
// case is needed since there is no way to force the TXC (transmit
// complete) bit to 1 during initialization
if (!_written)
return;
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
while (TEST(M_UCSRxB, M_UDRIEx) || !TEST(M_UCSRxA, M_TXCx)) {
if (!TEST(SREG, SREG_I) && TEST(M_UCSRxB, M_UDRIEx))
// Interrupts are globally disabled, but the DR empty
// interrupt should be enabled, so poll the DR empty flag to
// prevent deadlock
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!ISRS_ENABLED()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) {
// If there is more space, send an extra character
if (TEST(M_UCSRxA, M_UDREx))
_tx_udr_empty_irq();
sw_barrier();
}
}
// If we get here, nothing is queued anymore (DRIE is disabled) and
// the hardware finished tranmission (TXC is set).
else {
// Wait until everything was transmitted
while (tx_buffer.head != tx_buffer.tail || !TEST(M_UCSRxA, M_TXCx)) sw_barrier();
}
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
#else // TX_BUFFER_SIZE == 0
void MarlinSerial::write(const uint8_t c) {
#if ENABLED(SERIAL_XON_XOFF)
// Do a priority insertion of an XON/XOFF char, if needed.
const uint8_t state = xon_xoff_state;
if (!(state & XON_XOFF_CHAR_SENT)) {
writeNoHandshake(state & XON_XOFF_CHAR_MASK);
xon_xoff_state = state | XON_XOFF_CHAR_SENT;
}
#endif
writeNoHandshake(c);
}
void MarlinSerial::writeNoHandshake(uint8_t c) {
while (!TEST(M_UCSRxA, M_UDREx)) {/* nada */}
_written = true;
while (!TEST(M_UCSRxA, M_UDREx)) sw_barrier();
M_UDRx = c;
}
void MarlinSerial::flushTX(void) {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// Wait until everything was transmitted
while (!TEST(M_UCSRxA, M_TXCx)) sw_barrier();
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
#endif // TX_BUFFER_SIZE == 0
/**
@@ -437,13 +612,9 @@
}
void MarlinSerial::print(long n, int base) {
if (base == 0)
write(n);
if (base == 0) write(n);
else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
if (n < 0) { print('-'); n = -n; }
printNumber(n, 10);
}
else
+30 -15
View File
@@ -26,10 +26,11 @@
*
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
*/
#ifndef MARLINSERIAL_H
#define MARLINSERIAL_H
#ifndef _MARLINSERIAL_H_
#define _MARLINSERIAL_H_
#include "MarlinConfig.h"
@@ -59,6 +60,9 @@
#define M_TXCx SERIAL_REGNAME(TXC,SERIAL_PORT,)
#define M_RXCIEx SERIAL_REGNAME(RXCIE,SERIAL_PORT,)
#define M_UDREx SERIAL_REGNAME(UDRE,SERIAL_PORT,)
#define M_FEx SERIAL_REGNAME(FE,SERIAL_PORT,)
#define M_DORx SERIAL_REGNAME(DOR,SERIAL_PORT,)
#define M_UPEx SERIAL_REGNAME(UPE,SERIAL_PORT,)
#define M_UDRIEx SERIAL_REGNAME(UDRIE,SERIAL_PORT,)
#define M_UDRx SERIAL_REGNAME(UDR,SERIAL_PORT,)
#define M_UBRRxH SERIAL_REGNAME(UBRR,SERIAL_PORT,H)
@@ -97,11 +101,19 @@
extern uint8_t rx_dropped_bytes;
#endif
#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
extern uint8_t rx_buffer_overruns;
#endif
#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
extern uint8_t rx_framing_errors;
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
extern ring_buffer_pos_t rx_max_enqueued;
#endif
class MarlinSerial { //: public Stream
class MarlinSerial {
public:
MarlinSerial() {};
@@ -111,27 +123,25 @@
static int read(void);
static void flush(void);
static ring_buffer_pos_t available(void);
static void checkRx(void);
static void write(const uint8_t c);
#if TX_BUFFER_SIZE > 0
static uint8_t availableForWrite(void);
static void flushTX(void);
#endif
static void writeNoHandshake(const uint8_t c);
static void flushTX(void);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE static uint32_t dropped() { return rx_dropped_bytes; }
#endif
#if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
FORCE_INLINE static uint32_t buffer_overruns() { return rx_buffer_overruns; }
#endif
#if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
FORCE_INLINE static uint32_t framing_errors() { return rx_framing_errors; }
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return rx_max_enqueued; }
#endif
private:
static void printNumber(unsigned long, const uint8_t);
static void printFloat(double, uint8_t);
public:
FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
@@ -155,6 +165,11 @@
static void println(unsigned long, int = DEC);
static void println(double, int = 2);
static void println(void);
operator bool() { return true; }
private:
static void printNumber(unsigned long, const uint8_t);
static void printFloat(double, uint8_t);
};
extern MarlinSerial customizedSerial;
@@ -166,4 +181,4 @@
extern HardwareSerial bluetoothSerial;
#endif
#endif // MARLINSERIAL_H
#endif // _MARLINSERIAL_H_
+507 -308
View File
File diff suppressed because it is too large Load Diff
+304 -208
View File
@@ -22,11 +22,9 @@
/**
* This module is off by default, but can be enabled to facilitate the display of
* extra debug information during code development. It assumes the existence of a
* Max7219 LED Matrix. A suitable device can be obtained on eBay similar to this:
* http://www.ebay.com/itm/191781645249 for under $2.00 including shipping.
* extra debug information during code development.
*
* Just connect up +5v and GND to give it power, then connect up the pins assigned
* Just connect up 5V and GND to give it power, then connect up the pins assigned
* in Configuration_adv.h. For example, on the Re-ARM you could use:
*
* #define MAX7219_CLK_PIN 77
@@ -35,26 +33,14 @@
*
* Max7219_init() is called automatically at startup, and then there are a number of
* support functions available to control the LEDs in the 8x8 grid.
*
* void Max7219_init();
* void Max7219_PutByte(uint8_t data);
* void Max7219(uint8_t reg, uint8_t data);
* void Max7219_LED_On(uint8_t col, uint8_t row);
* void Max7219_LED_Off(uint8_t col, uint8_t row);
* void Max7219_LED_Toggle(uint8_t col, uint8_t row);
* void Max7219_Clear_Row(uint8_t row);
* void Max7219_Clear_Column(uint8_t col);
* void Max7219_Set_Row(uint8_t row, uint8_t val);
* void Max7219_Set_2_Rows(uint8_t row, uint16_t val);
* void Max7219_Set_4_Rows(uint8_t row, uint32_t val);
* void Max7219_Set_Column(uint8_t col, uint8_t val);
* void Max7219_idle_tasks();
*/
#include "MarlinConfig.h"
#if ENABLED(MAX7219_DEBUG)
#define MAX7219_ERRORS // Disable to save 406 bytes of Program Memory
#include "Max7219_Debug_LEDs.h"
#include "planner.h"
@@ -64,11 +50,43 @@
static uint8_t LEDs[8] = { 0 };
#ifndef MAX7219_ROTATE
#define MAX7219_ROTATE 0
#endif
#define _ROT ((MAX7219_ROTATE + 360) % 360)
#if _ROT == 0
#define _ROW_ y
#define _COL_ x
#define XOR_7219(x, y) LEDs[y] ^= _BV(7 - x)
#define BIT_7219(x, y) TEST(LEDs[y], 7 - x)
#define SEND_7219(R,V) Max7219(max7219_reg_digit0 + R, V)
#elif _ROT == 90
#define _ROW_ x
#define _COL_ y
#define XOR_7219(x, y) LEDs[x] ^= _BV(y)
#define BIT_7219(x, y) TEST(LEDs[x], y)
#define SEND_7219(R,V) Max7219(max7219_reg_digit0 + R, V)
#elif _ROT == 180
#define _ROW_ y
#define _COL_ x
#define XOR_7219(x, y) LEDs[y] ^= _BV(x)
#define BIT_7219(x, y) TEST(LEDs[y], x)
#define SEND_7219(R,V) Max7219(max7219_reg_digit7 - R, V)
#elif _ROT == 270
#define _ROW_ x
#define _COL_ y
#define XOR_7219(x, y) LEDs[x] ^= _BV(7 - y)
#define BIT_7219(x, y) TEST(LEDs[x], 7 - y)
#define SEND_7219(R,V) Max7219(max7219_reg_digit7 - R, V)
#else
#error "MAX7219_ROTATE must be a multiple of +/- 90°."
#endif
// Delay for 0.1875µs (16MHz AVR) or 0.15µs (20MHz AVR)
#define SIG_DELAY() DELAY_NS(188)
void Max7219_PutByte(uint8_t data) {
CRITICAL_SECTION_START
CRITICAL_SECTION_START;
for (uint8_t i = 8; i--;) {
SIG_DELAY();
WRITE(MAX7219_CLK_PIN, LOW); // tick
@@ -79,12 +97,12 @@ void Max7219_PutByte(uint8_t data) {
SIG_DELAY();
data <<= 1;
}
CRITICAL_SECTION_END
CRITICAL_SECTION_END;
}
void Max7219(const uint8_t reg, const uint8_t data) {
SIG_DELAY();
CRITICAL_SECTION_START
CRITICAL_SECTION_START;
WRITE(MAX7219_LOAD_PIN, LOW); // begin
SIG_DELAY();
Max7219_PutByte(reg); // specify register
@@ -94,126 +112,170 @@ void Max7219(const uint8_t reg, const uint8_t data) {
WRITE(MAX7219_LOAD_PIN, LOW); // and tell the chip to load the data
SIG_DELAY();
WRITE(MAX7219_LOAD_PIN, HIGH);
CRITICAL_SECTION_END
CRITICAL_SECTION_END;
SIG_DELAY();
}
void Max7219_LED_Set(const uint8_t col, const uint8_t row, const bool on) {
if (row > 7 || col > 7) {
SERIAL_ECHOPAIR("??? Max7219_LED_Set(", (int)row);
SERIAL_ECHOPAIR(",", (int)col);
SERIAL_ECHOLNPGM(")");
return;
#if ENABLED(MAX7219_NUMERIC)
// Draw an integer with optional leading zeros and optional decimal point
void Max7219_Print(const uint8_t start, int16_t value, uint8_t size, const bool leadzero=false, bool dec=false) {
constexpr uint8_t led_numeral[10] = { 0x7E, 0x60, 0x6D, 0x79, 0x63, 0x5B, 0x5F, 0x70, 0x7F, 0x7A },
led_decimal = 0x80, led_minus = 0x01;
bool blank = false, neg = value < 0;
if (neg) value *= -1;
while (size--) {
const bool minus = neg && blank;
if (minus) neg = false;
Max7219(
max7219_reg_digit0 + start + size,
minus ? led_minus : blank ? 0x00 : led_numeral[value % 10] | (dec ? led_decimal : 0x00)
);
value /= 10;
if (!value && !leadzero) blank = true;
dec = false;
}
}
if (TEST(LEDs[col], row) == on) return; // if LED is already on/off, leave alone
if (on) SBI(LEDs[col], row); else CBI(LEDs[col], row);
Max7219(8 - col, LEDs[col]);
// Draw a float with a decimal point and optional digits
void Max7219_Print(const uint8_t start, const float value, const uint8_t pre_size, const uint8_t post_size, const bool leadzero=false) {
if (pre_size) Max7219_Print(start, value, pre_size, leadzero, !!post_size);
if (post_size) {
const int16_t after = ABS(value) * (10 ^ post_size);
Max7219_Print(start + pre_size, after, post_size, true);
}
}
#endif // MAX7219_NUMERIC
inline void Max7219_Error(const char * const func, const int32_t v1, const int32_t v2=-1) {
#if ENABLED(MAX7219_ERRORS)
SERIAL_ECHOPGM("??? ");
serialprintPGM(func);
SERIAL_CHAR('(');
SERIAL_ECHO(v1);
if (v2 > 0) SERIAL_ECHOPAIR(", ", v2);
SERIAL_CHAR(')');
SERIAL_EOL();
#else
UNUSED(func); UNUSED(v1); UNUSED(v2);
#endif
}
void Max7219_LED_On(const uint8_t col, const uint8_t row) {
if (row > 7 || col > 7) {
SERIAL_ECHOPAIR("??? Max7219_LED_On(", (int)col);
SERIAL_ECHOPAIR(",", (int)row);
SERIAL_ECHOLNPGM(")");
return;
}
Max7219_LED_Set(col, row, true);
inline uint8_t flipped(const uint8_t bits) {
uint8_t outbits = 0;
for (uint8_t b = 0; b < 8; b++)
if (bits & _BV(b)) outbits |= _BV(7 - b);
return outbits;
}
void Max7219_LED_Off(const uint8_t col, const uint8_t row) {
if (row > 7 || col > 7) {
SERIAL_ECHOPAIR("??? Max7219_LED_Off(", (int)row);
SERIAL_ECHOPAIR(",", (int)col);
SERIAL_ECHOLNPGM(")");
return;
}
Max7219_LED_Set(col, row, false);
// Modify a single LED bit and send the changed line
void Max7219_LED_Set(const uint8_t x, const uint8_t y, const bool on) {
if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Set"), x, y);
if (BIT_7219(x, y) == on) return;
XOR_7219(x, y);
SEND_7219(_ROW_, LEDs[_ROW_]);
}
void Max7219_LED_Toggle(const uint8_t col, const uint8_t row) {
if (row > 7 || col > 7) {
SERIAL_ECHOPAIR("??? Max7219_LED_Toggle(", (int)row);
SERIAL_ECHOPAIR(",", (int)col);
SERIAL_ECHOLNPGM(")");
return;
}
if (TEST(LEDs[row], col))
Max7219_LED_Off(col, row);
else
Max7219_LED_On(col, row);
void Max7219_LED_On(const uint8_t x, const uint8_t y) {
if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_On"), x, y);
Max7219_LED_Set(x, y, true);
}
void Max7219_Clear_Column(const uint8_t col) {
if (col > 7) {
SERIAL_ECHOPAIR("??? Max7219_Clear_Column(", (int)col);
SERIAL_ECHOLNPGM(")");
return;
}
LEDs[col] = 0;
Max7219(8 - col, LEDs[col]);
void Max7219_LED_Off(const uint8_t x, const uint8_t y) {
if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Off"), x, y);
Max7219_LED_Set(x, y, false);
}
void Max7219_Clear_Row(const uint8_t row) {
if (row > 7) {
SERIAL_ECHOPAIR("??? Max7219_Clear_Row(", (int)row);
SERIAL_ECHOLNPGM(")");
return;
}
for (uint8_t c = 0; c <= 7; c++)
Max7219_LED_Off(c, row);
void Max7219_LED_Toggle(const uint8_t x, const uint8_t y) {
if (x > 7 || y > 7) return Max7219_Error(PSTR("Max7219_LED_Toggle"), x, y);
Max7219_LED_Set(x, y, !BIT_7219(x, y));
}
void Max7219_Set_Row(const uint8_t row, const uint8_t val) {
if (row > 7) {
SERIAL_ECHOPAIR("??? Max7219_Set_Row(", (int)row);
SERIAL_ECHOPAIR(",", (int)val);
SERIAL_ECHOLNPGM(")");
return;
}
for (uint8_t b = 0; b <= 7; b++)
if (TEST(val, b))
Max7219_LED_On(7 - b, row);
else
Max7219_LED_Off(7 - b, row);
inline void _Max7219_Set_Reg(const uint8_t reg, const uint8_t val) {
LEDs[reg] = val;
SEND_7219(reg, val);
}
void Max7219_Set_2_Rows(const uint8_t row, const uint16_t val) {
if (row > 6) {
SERIAL_ECHOPAIR("??? Max7219_Set_2_Rows(", (int)row);
SERIAL_ECHOPAIR(",", (int)val);
SERIAL_ECHOLNPGM(")");
return;
}
Max7219_Set_Row(row + 1, (val >> 8) & 0xFF);
Max7219_Set_Row(row + 0, (val ) & 0xFF);
void Max7219_Set_Row(const uint8_t _ROW_, const uint8_t val) {
if (_ROW_ > 7) return Max7219_Error(PSTR("Max7219_Set_Row"), _ROW_);
#if _ROT == 90
for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Set(7 - _COL_, _ROW_, TEST(val, _COL_));
#elif _ROT == 180
_Max7219_Set_Reg(_ROW_, flipped(val));
#elif _ROT == 270
for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _COL_));
#else
_Max7219_Set_Reg(_ROW_, val);
#endif
}
void Max7219_Set_4_Rows(const uint8_t row, const uint32_t val) {
if (row > 4) {
SERIAL_ECHOPAIR("??? Max7219_Set_4_Rows(", (int)row);
SERIAL_ECHOPAIR(",", (long)val);
SERIAL_ECHOLNPGM(")");
return;
}
Max7219_Set_Row(row + 3, (val >> 24) & 0xFF);
Max7219_Set_Row(row + 2, (val >> 16) & 0xFF);
Max7219_Set_Row(row + 1, (val >> 8) & 0xFF);
Max7219_Set_Row(row + 0, (val ) & 0xFF);
void Max7219_Clear_Row(const uint8_t _ROW_) {
if (_ROW_ > 7) return Max7219_Error(PSTR("Max7219_Clear_Row"), _ROW_);
#if _ROT == 90 || _ROT == 270
for (uint8_t _COL_ = 0; _COL_ <= 7; _COL_++) Max7219_LED_Off(_COL_, _ROW_);
#else
_Max7219_Set_Reg(_ROW_, 0);
#endif
}
void Max7219_Set_Column(const uint8_t col, const uint8_t val) {
if (col > 7) {
SERIAL_ECHOPAIR("??? Max7219_Column(", (int)col);
SERIAL_ECHOPAIR(",", (int)val);
SERIAL_ECHOLNPGM(")");
return;
}
LEDs[col] = val;
Max7219(8 - col, LEDs[col]);
void Max7219_Set_Column(const uint8_t _COL_, const uint8_t val) {
if (_COL_ > 7) return Max7219_Error(PSTR("Max7219_Set_Column"), _COL_);
#if _ROT == 90
_Max7219_Set_Reg(_COL_, val);
#elif _ROT == 180
for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _ROW_));
#elif _ROT == 270
_Max7219_Set_Reg(_COL_, flipped(val));
#else
for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Set(_COL_, _ROW_, TEST(val, _ROW_));
#endif
}
void Max7219_Clear_Column(const uint8_t _COL_) {
if (_COL_ > 7) return Max7219_Error(PSTR("Max7219_Clear_Column"), _COL_);
#if _ROT == 90 || _ROT == 270
_Max7219_Set_Reg(_COL_, 0);
#else
for (uint8_t _ROW_ = 0; _ROW_ <= 7; _ROW_++) Max7219_LED_Off(_COL_, _ROW_);
#endif
}
void Max7219_Clear() {
for (uint8_t r = 0; r < 8; r++) _Max7219_Set_Reg(r, 0);
}
void Max7219_Set_2_Rows(const uint8_t y, uint16_t val) {
if (y > 6) return Max7219_Error(PSTR("Max7219_Set_2_Rows"), y, val);
Max7219_Set_Row(y + 0, val & 0xFF); val >>= 8;
Max7219_Set_Row(y + 1, val & 0xFF);
}
void Max7219_Set_4_Rows(const uint8_t y, uint32_t val) {
if (y > 4) return Max7219_Error(PSTR("Max7219_Set_4_Rows"), y, val);
Max7219_Set_Row(y + 0, val & 0xFF); val >>= 8;
Max7219_Set_Row(y + 1, val & 0xFF); val >>= 8;
Max7219_Set_Row(y + 2, val & 0xFF); val >>= 8;
Max7219_Set_Row(y + 3, val & 0xFF);
}
void Max7219_Set_2_Columns(const uint8_t x, uint16_t val) {
if (x > 6) return Max7219_Error(PSTR("Max7219_Set_2_Columns"), x, val);
Max7219_Set_Column(x + 0, val & 0xFF); val >>= 8;
Max7219_Set_Column(x + 1, val & 0xFF);
}
void Max7219_Set_4_Columns(const uint8_t x, uint32_t val) {
if (x > 4) return Max7219_Error(PSTR("Max7219_Set_4_Columns"), x, val);
Max7219_Set_Column(x + 0, val & 0xFF); val >>= 8;
Max7219_Set_Column(x + 1, val & 0xFF); val >>= 8;
Max7219_Set_Column(x + 2, val & 0xFF); val >>= 8;
Max7219_Set_Column(x + 3, val & 0xFF);
}
void Max7219_register_setup() {
//initiation of the max 7219
// Initialize the Max7219
Max7219(max7219_reg_scanLimit, 0x07);
Max7219(max7219_reg_decodeMode, 0x00); // using an led matrix (not digits)
Max7219(max7219_reg_shutdown, 0x01); // not in shutdown mode
@@ -222,135 +284,169 @@ void Max7219_register_setup() {
// range: 0x00 to 0x0F
}
void Max7219_init() {
uint8_t i, x, y;
#ifdef MAX7219_INIT_TEST
#if (MAX7219_INIT_TEST + 0) == 2
inline void Max7219_spiral(const bool on, const uint16_t del) {
constexpr int8_t way[] = { 1, 0, 0, 1, -1, 0, 0, -1 };
int8_t px = 0, py = 0, dir = 0;
for (uint8_t i = 64; i--;) {
Max7219_LED_Set(px, py, on);
delay(del);
const int8_t x = px + way[dir], y = py + way[dir + 1];
if (!WITHIN(x, 0, 7) || !WITHIN(y, 0, 7) || BIT_7219(x, y) == on) dir = (dir + 2) & 0x7;
px += way[dir]; py += way[dir + 1];
}
}
#else
inline void Max7219_colset(const uint8_t x, const bool on) {
for (uint8_t y = 0; y <= 7; y++) Max7219_LED_Set(x, y, on);
}
inline void Max7219_sweep(const int8_t dir, const uint16_t ms, const bool on) {
uint8_t x = dir > 0 ? 0 : 7;
for (uint8_t i = 8; i--; x += dir) {
Max7219_Set_Column(x, on ? 0xFF : 0x00);
delay(ms);
}
}
#endif
#endif // MAX7219_INIT_TEST
void Max7219_init() {
SET_OUTPUT(MAX7219_DIN_PIN);
SET_OUTPUT(MAX7219_CLK_PIN);
OUT_WRITE(MAX7219_LOAD_PIN, HIGH);
delay(1);
Max7219_register_setup();
for (i = 0; i <= 7; i++) { // empty registers, turn all LEDs off
for (uint8_t i = 0; i <= 7; i++) { // Empty registers to turn all LEDs off
LEDs[i] = 0x00;
Max7219(i + 1, 0);
Max7219(max7219_reg_digit0 + i, 0);
}
for (x = 0; x <= 7; x++) // Do an aesthetically pleasing pattern to fully test
for (y = 0; y <= 7; y++) { // the Max7219 module and LEDs. First, turn them
Max7219_LED_On(y, x); // all on.
delay(3);
}
for (x = 0; x <= 7; x++) // Now, turn them all off.
for (y = 0; y <= 7; y++) {
Max7219_LED_Off(y, x);
delay(3); // delay() is OK here. Max7219_init() is only called from
} // setup() and nothing is running yet.
delay(150);
for (x = 8; x--;) // Now, do the same thing from the opposite direction
for (y = 0; y <= 7; y++) {
Max7219_LED_On(y, x);
delay(2);
}
for (x = 8; x--;)
for (y = 0; y <= 7; y++) {
Max7219_LED_Off(y, x);
delay(2);
}
#ifdef MAX7219_INIT_TEST
#if (MAX7219_INIT_TEST + 0) == 2
Max7219_spiral(true, 8);
delay(150);
Max7219_spiral(false, 8);
#else
// Do an aesthetically-pleasing pattern to fully test the Max7219 module and LEDs.
// Light up and turn off columns, both forward and backward.
Max7219_sweep(1, 20, true);
Max7219_sweep(1, 20, false);
delay(150);
Max7219_sweep(-1, 20, true);
Max7219_sweep(-1, 20, false);
#endif
#endif
}
/**
* These are sample debug features to demonstrate the usage of the 8x8 LED Matrix for debug purposes.
* There is very little CPU burden added to the system by displaying information within the idle()
* task.
*
* But with that said, if your debugging can be facilitated by making calls into the library from
* other places in the code, feel free to do it. The CPU burden for a few calls to toggle an LED
* or clear a row is not very significant.
* This code demonstrates some simple debugging using a single 8x8 LED Matrix. If your feature could
* benefit from matrix display, add its code here. Very little processing is required, so the 7219 is
* ideal for debugging when realtime feedback is important but serial output can't be used.
*/
// Apply changes to update a marker
inline void Max7219_Mark16(const uint8_t y, const uint8_t v1, const uint8_t v2) {
Max7219_LED_Off(v1 & 0x7, y + (v1 >= 8));
Max7219_LED_On(v2 & 0x7, y + (v2 >= 8));
}
// Apply changes to update a tail-to-head range
inline void Max7219_Range16(const uint8_t y, const uint8_t ot, const uint8_t nt, const uint8_t oh, const uint8_t nh) {
if (ot != nt) for (uint8_t n = ot & 0xF; n != (nt & 0xF) && n != (nh & 0xF); n = (n + 1) & 0xF)
Max7219_LED_Off(n & 0x7, y + (n >= 8));
if (oh != nh) for (uint8_t n = (oh + 1) & 0xF; n != ((nh + 1) & 0xF); n = (n + 1) & 0xF)
Max7219_LED_On(n & 0x7, y + (n >= 8));
}
// Apply changes to update a quantity
inline void Max7219_Quantity16(const uint8_t y, const uint8_t ov, const uint8_t nv) {
for (uint8_t i = MIN(nv, ov); i < MAX(nv, ov); i++)
Max7219_LED_Set(i >> 1, y + (i & 1), nv >= ov);
}
void Max7219_idle_tasks() {
#if MAX7219_DEBUG_STEPPER_HEAD || MAX7219_DEBUG_STEPPER_TAIL || MAX7219_DEBUG_STEPPER_QUEUE
CRITICAL_SECTION_START
#if MAX7219_DEBUG_STEPPER_HEAD || MAX7219_DEBUG_STEPPER_QUEUE
#define MAX7219_USE_HEAD (defined(MAX7219_DEBUG_PLANNER_HEAD) || defined(MAX7219_DEBUG_PLANNER_QUEUE))
#define MAX7219_USE_TAIL (defined(MAX7219_DEBUG_PLANNER_TAIL) || defined(MAX7219_DEBUG_PLANNER_QUEUE))
#if MAX7219_USE_HEAD || MAX7219_USE_TAIL
CRITICAL_SECTION_START;
#if MAX7219_USE_HEAD
const uint8_t head = planner.block_buffer_head;
#endif
#if MAX7219_DEBUG_STEPPER_TAIL || MAX7219_DEBUG_STEPPER_QUEUE
#if MAX7219_USE_TAIL
const uint8_t tail = planner.block_buffer_tail;
#endif
CRITICAL_SECTION_END
CRITICAL_SECTION_END;
#endif
static uint16_t refresh_cnt = 0; // The Max7219 circuit boards available for several dollars on eBay
if (refresh_cnt++ > 50000) { // are vulnerable to electrical noise, especially with long wires
Max7219_register_setup(); // next to high current wires. If the display becomes corrupted due
Max7219_LED_Toggle(7, 0); // to electrical noise, this will fix it within a couple of seconds.
#if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE)
static uint8_t refresh_cnt; // = 0
constexpr uint16_t refresh_limit = 5;
static millis_t next_blink = 0;
const millis_t ms = millis();
const bool do_blink = ELAPSED(ms, next_blink);
#else
static uint16_t refresh_cnt; // = 0
constexpr bool do_blink = true;
constexpr uint16_t refresh_limit = 50000;
#endif
// Some Max7219 units are vulnerable to electrical noise, especially
// with long wires next to high current wires. If the display becomes
// corrupted, this will fix it within a couple seconds.
if (do_blink && ++refresh_cnt >= refresh_limit) {
refresh_cnt = 0;
Max7219_register_setup();
}
#if ENABLED(MAX7219_DEBUG_PRINTER_ALIVE)
static millis_t next_blink = 0;
if (ELAPSED(millis(), next_blink)) {
if (do_blink) {
Max7219_LED_Toggle(7, 7);
next_blink = millis() + 750;
next_blink = ms + 1000;
}
#endif
#ifdef MAX7219_DEBUG_STEPPER_HEAD
static int16_t last_head_cnt = 0;
if (last_head_cnt != head) {
if (last_head_cnt < 8)
Max7219_LED_Off(MAX7219_DEBUG_STEPPER_HEAD, last_head_cnt);
else
Max7219_LED_Off(MAX7219_DEBUG_STEPPER_HEAD + 1, last_head_cnt - 8);
#if defined(MAX7219_DEBUG_PLANNER_HEAD) && defined(MAX7219_DEBUG_PLANNER_TAIL) && MAX7219_DEBUG_PLANNER_HEAD == MAX7219_DEBUG_PLANNER_TAIL
static int16_t last_head_cnt = 0xF, last_tail_cnt = 0xF;
if (last_head_cnt != head || last_tail_cnt != tail) {
Max7219_Range16(MAX7219_DEBUG_PLANNER_HEAD, last_tail_cnt, tail, last_head_cnt, head);
last_head_cnt = head;
if (head < 8)
Max7219_LED_On(MAX7219_DEBUG_STEPPER_HEAD, head);
else
Max7219_LED_On(MAX7219_DEBUG_STEPPER_HEAD + 1, head - 8);
}
#endif
#ifdef MAX7219_DEBUG_STEPPER_TAIL
static int16_t last_tail_cnt = 0;
if (last_tail_cnt != tail) {
if (last_tail_cnt < 8)
Max7219_LED_Off(MAX7219_DEBUG_STEPPER_TAIL, last_tail_cnt);
else
Max7219_LED_Off(MAX7219_DEBUG_STEPPER_TAIL + 1, last_tail_cnt - 8);
last_tail_cnt = tail;
if (tail < 8)
Max7219_LED_On(MAX7219_DEBUG_STEPPER_TAIL, tail);
else
Max7219_LED_On(MAX7219_DEBUG_STEPPER_TAIL + 1, tail - 8);
}
#else
#ifdef MAX7219_DEBUG_PLANNER_HEAD
static int16_t last_head_cnt = 0x1;
if (last_head_cnt != head) {
Max7219_Mark16(MAX7219_DEBUG_PLANNER_HEAD, last_head_cnt, head);
last_head_cnt = head;
}
#endif
#ifdef MAX7219_DEBUG_PLANNER_TAIL
static int16_t last_tail_cnt = 0x1;
if (last_tail_cnt != tail) {
Max7219_Mark16(MAX7219_DEBUG_PLANNER_TAIL, last_tail_cnt, tail);
last_tail_cnt = tail;
}
#endif
#endif
#ifdef MAX7219_DEBUG_STEPPER_QUEUE
#ifdef MAX7219_DEBUG_PLANNER_QUEUE
static int16_t last_depth = 0;
int16_t current_depth = head - tail;
if (current_depth != last_depth) { // usually, no update will be needed.
if (current_depth < 0) current_depth += BLOCK_BUFFER_SIZE;
NOMORE(current_depth, BLOCK_BUFFER_SIZE);
NOMORE(current_depth, 16); // if the BLOCK_BUFFER_SIZE is greater than 16, two lines
// of LEDs is enough to see if the buffer is draining
const uint8_t st = MIN(current_depth, last_depth),
en = MAX(current_depth, last_depth);
if (current_depth < last_depth)
for (uint8_t i = st; i <= en; i++) // clear the highest order LEDs
Max7219_LED_Off(MAX7219_DEBUG_STEPPER_QUEUE + (i & 1), i / 2);
else
for (uint8_t i = st; i <= en; i++) // set the LEDs to current depth
Max7219_LED_On(MAX7219_DEBUG_STEPPER_QUEUE + (i & 1), i / 2);
const int16_t current_depth = (head - tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1) & 0xF;
if (current_depth != last_depth) {
Max7219_Quantity16(MAX7219_DEBUG_PLANNER_QUEUE, last_depth, current_depth);
last_depth = current_depth;
}
#endif
+25 -29
View File
@@ -22,11 +22,9 @@
/**
* This module is off by default, but can be enabled to facilitate the display of
* extra debug information during code development. It assumes the existence of a
* Max7219 LED Matrix. A suitable device can be obtained on eBay similar to this:
* http://www.ebay.com/itm/191781645249 for under $2.00 including shipping.
* extra debug information during code development.
*
* Just connect up +5v and GND to give it power, then connect up the pins assigned
* Just connect up 5V and GND to give it power, then connect up the pins assigned
* in Configuration_adv.h. For example, on the Re-ARM you could use:
*
* #define MAX7219_CLK_PIN 77
@@ -35,28 +33,13 @@
*
* Max7219_init() is called automatically at startup, and then there are a number of
* support functions available to control the LEDs in the 8x8 grid.
*
* void Max7219_init();
* void Max7219_PutByte(uint8_t data);
* void Max7219(uint8_t reg, uint8_t data);
* void Max7219_LED_Set(uint8_t row, uint8_t col, bool on);
* void Max7219_LED_On(uint8_t col, uint8_t row);
* void Max7219_LED_Off(uint8_t col, uint8_t row);
* void Max7219_LED_Toggle(uint8_t row, uint8_t col);
* void Max7219_Clear_Row(uint8_t row);
* void Max7219_Clear_Column(uint8_t col);
* void Max7219_Set_Row(uint8_t row, uint8_t val);
* void Max7219_Set_2_Rows(uint8_t row, uint16_t val);
* void Max7219_Set_4_Rows(uint8_t row, uint32_t val);
* void Max7219_Set_Column(uint8_t col, uint8_t val);
* void Max7219_idle_tasks();
*/
#ifndef __MAX7219_DEBUG_LEDS_H__
#define __MAX7219_DEBUG_LEDS_H__
//
// define max7219 registers
// MAX7219 registers
//
#define max7219_reg_noop 0x00
#define max7219_reg_digit0 0x01
@@ -68,23 +51,36 @@
#define max7219_reg_digit6 0x07
#define max7219_reg_digit7 0x08
#define max7219_reg_intensity 0x0A
#define max7219_reg_displayTest 0x0F
#define max7219_reg_decodeMode 0x09
#define max7219_reg_intensity 0x0A
#define max7219_reg_scanLimit 0x0B
#define max7219_reg_shutdown 0x0C
#define max7219_reg_displayTest 0x0F
void Max7219_init();
void Max7219_PutByte(uint8_t data);
// Set a single register (e.g., a whole native row)
void Max7219(const uint8_t reg, const uint8_t data);
void Max7219_LED_Set(const uint8_t row, const uint8_t col, const bool on);
void Max7219_LED_On(const uint8_t row, const uint8_t col);
void Max7219_LED_Off(const uint8_t row, const uint8_t col);
void Max7219_LED_Toggle(const uint8_t row, const uint8_t col);
void Max7219_Clear_Row(const uint8_t row);
void Max7219_Clear_Column(const uint8_t col);
void Max7219_Set_Row(const uint8_t row, const uint8_t val);
// Set a single LED by XY coordinate
void Max7219_LED_Set(const uint8_t x, const uint8_t y, const bool on);
void Max7219_LED_On(const uint8_t x, const uint8_t y);
void Max7219_LED_Off(const uint8_t x, const uint8_t y);
void Max7219_LED_Toggle(const uint8_t x, const uint8_t y);
// Set all 8 LEDs in a single column
void Max7219_Set_Column(const uint8_t col, const uint8_t val);
void Max7219_Clear_Column(const uint8_t col);
// Set all 8 LEDs in a single row
void Max7219_Set_Row(const uint8_t row, const uint8_t val);
void Max7219_Clear_Row(const uint8_t row);
// Quickly clear the whole matrix
void Max7219_Clear();
// Apply custom code to update the matrix
void Max7219_idle_tasks();
#endif // __MAX7219_DEBUG_LEDS_H__
+23 -9
View File
@@ -54,7 +54,9 @@
/**
* Warnings for old configurations
*/
#if !defined(X_BED_SIZE) || !defined(Y_BED_SIZE)
#ifndef MOTHERBOARD
#error "MOTHERBOARD is required. Please update your configuration."
#elif !defined(X_BED_SIZE) || !defined(Y_BED_SIZE)
#error "X_BED_SIZE and Y_BED_SIZE are now required! Please update your configuration."
#elif WATCH_TEMP_PERIOD > 500
#error "WATCH_TEMP_PERIOD now uses seconds instead of milliseconds."
@@ -273,6 +275,20 @@
#error "FILAMENT_CHANGE_LOAD_LENGTH is now FILAMENT_CHANGE_FAST_LOAD_LENGTH. Please update your configuration."
#elif ENABLED(LEVEL_BED_CORNERS) && !defined(LEVEL_CORNERS_INSET)
#error "LEVEL_BED_CORNERS requires a LEVEL_CORNERS_INSET value. Please update your Configuration.h."
#elif defined(BEZIER_JERK_CONTROL)
#error "BEZIER_JERK_CONTROL is now S_CURVE_ACCELERATION. Please update your configuration."
#elif defined(JUNCTION_DEVIATION_FACTOR)
#error "JUNCTION_DEVIATION_FACTOR is now JUNCTION_DEVIATION_MM. Please update your configuration."
#elif defined(JUNCTION_ACCELERATION_FACTOR)
#error "JUNCTION_ACCELERATION_FACTOR is obsolete. Delete it from Configuration_adv.h."
#elif defined(JUNCTION_ACCELERATION)
#error "JUNCTION_ACCELERATION is obsolete. Delete it from Configuration_adv.h."
#elif defined(MAX7219_DEBUG_STEPPER_HEAD)
#error "MAX7219_DEBUG_STEPPER_HEAD is now MAX7219_DEBUG_PLANNER_HEAD. Please update your configuration."
#elif defined(MAX7219_DEBUG_STEPPER_TAIL)
#error "MAX7219_DEBUG_STEPPER_TAIL is now MAX7219_DEBUG_PLANNER_TAIL. Please update your configuration."
#elif defined(MAX7219_DEBUG_STEPPER_QUEUE)
#error "MAX7219_DEBUG_STEPPER_QUEUE is now MAX7219_DEBUG_PLANNER_QUEUE. Please update your configuration."
#endif
#define BOARD_MKS_13 -47
@@ -920,15 +936,11 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
*/
#if ENABLED(Z_SAFE_HOMING)
#if HAS_BED_PROBE
static_assert(WITHIN(Z_SAFE_HOMING_X_POINT, MIN_PROBE_X, MAX_PROBE_X),
"Z_SAFE_HOMING_X_POINT is outside the probe region.");
static_assert(WITHIN(Z_SAFE_HOMING_Y_POINT, MIN_PROBE_Y, MAX_PROBE_Y),
"Z_SAFE_HOMING_Y_POINT is outside the probe region.");
static_assert(WITHIN(Z_SAFE_HOMING_X_POINT, MIN_PROBE_X, MAX_PROBE_X), "Z_SAFE_HOMING_X_POINT is outside the probe region.");
static_assert(WITHIN(Z_SAFE_HOMING_Y_POINT, MIN_PROBE_Y, MAX_PROBE_Y), "Z_SAFE_HOMING_Y_POINT is outside the probe region.");
#else
static_assert(WITHIN(Z_SAFE_HOMING_X_POINT, X_MIN_POS, X_MAX_POS),
"Z_SAFE_HOMING_X_POINT can't be reached by the nozzle.");
static_assert(WITHIN(Z_SAFE_HOMING_Y_POINT, Y_MIN_POS, Y_MAX_POS),
"Z_SAFE_HOMING_Y_POINT can't be reached by the nozzle.");
static_assert(WITHIN(Z_SAFE_HOMING_X_POINT, X_MIN_POS, X_MAX_POS), "Z_SAFE_HOMING_X_POINT can't be reached by the nozzle.");
static_assert(WITHIN(Z_SAFE_HOMING_Y_POINT, Y_MIN_POS, Y_MAX_POS), "Z_SAFE_HOMING_Y_POINT can't be reached by the nozzle.");
#endif
#endif // Z_SAFE_HOMING
@@ -1482,6 +1494,8 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
#error "SENSORLESS_HOMING requires Z_MIN_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMIN when homing to Z_MIN."
#elif Z_SENSORLESS && Z_HOME_DIR == 1 && (DISABLED(Z_MAX_ENDSTOP_INVERTING) || DISABLED(ENDSTOPPULLUP_ZMAX))
#error "SENSORLESS_HOMING requires Z_MAX_ENDSTOP_INVERTING and ENDSTOPPULLUP_ZMAX when homing to Z_MAX."
#elif ENABLED(ENDSTOP_NOISE_FILTER)
#error "SENSORLESS_HOMING is incompatible with ENDSTOP_NOISE_FILTER."
#endif
#endif
+2 -2
View File
@@ -35,7 +35,7 @@
/**
* Marlin release version identifier
*/
#define SHORT_BUILD_VERSION "1.1.8-R6"
#define SHORT_BUILD_VERSION "1.1.8-R7"
/**
* Verbose version identifier which should contain a reference to the location
@@ -48,7 +48,7 @@
* here we define this default string as the date where the latest release
* version was tagged.
*/
#define STRING_DISTRIBUTION_DATE "2018-05-26"
#define STRING_DISTRIBUTION_DATE "2018-07-07"
/**
* Required minimum Configuration.h and Configuration_adv.h file versions.
+1 -1
View File
@@ -156,6 +156,6 @@
#define BOARD_TEENSY2 84 // Teensy++2.0 (AT90USB1286) - CLI compile: HARDWARE_MOTHERBOARD=84 make
#define BOARD_5DPRINT 88 // 5DPrint D8 Driver Board
#define MB(board) (MOTHERBOARD==BOARD_##board)
#define MB(board) (defined(BOARD_##board) && MOTHERBOARD==BOARD_##board)
#endif // __BOARDS_H
+26 -18
View File
@@ -98,8 +98,8 @@ void CardReader::lsDive(const char *prepend, SdFile parent, const char * const m
createFilename(dosFilename, p);
// Allocate enough stack space for the full path to a folder, trailing slash, and nul
bool prepend_is_empty = (prepend[0] == '\0');
int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(dosFilename) + 1 + 1;
const bool prepend_is_empty = (!prepend || prepend[0] == '\0');
const int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(dosFilename) + 1 + 1;
char path[len];
// Append the FOLDERNAME12/ to the passed string.
@@ -501,9 +501,13 @@ void CardReader::checkautostart() {
if (!cardOK) initsd();
if (cardOK) {
if (cardOK
#if ENABLED(POWER_LOSS_RECOVERY)
&& !jobRecoverFileExists() // Don't run auto#.g when a resume file exists
#endif
) {
char autoname[10];
sprintf_P(autoname, PSTR("auto%i.g"), autostart_index);
sprintf_P(autoname, PSTR("auto%i.g"), int(autostart_index));
dir_t p;
root.rewind();
while (root.readDir(&p, NULL) > 0) {
@@ -582,9 +586,8 @@ const char* CardReader::diveToFile(SdFile*& curDir, const char * const path, con
while (dirname_start) {
char * const dirname_end = strchr(dirname_start, '/');
if (dirname_end <= dirname_start) break;
char dosSubdirname[FILENAME_LENGTH];
const uint8_t len = dirname_end - dirname_start;
char dosSubdirname[len + 1];
strncpy(dosSubdirname, dirname_start, len);
dosSubdirname[len] = 0;
@@ -898,11 +901,7 @@ void CardReader::printingHasFinished() {
sdprinting = false;
#if ENABLED(POWER_LOSS_RECOVERY)
openJobRecoveryFile(false);
job_recovery_info.valid_head = job_recovery_info.valid_foot = 0;
(void)saveJobRecoveryInfo();
closeJobRecoveryFile();
job_recovery_commands_count = 0;
removeJobRecoveryFile();
#endif
#if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
@@ -948,20 +947,24 @@ void CardReader::printingHasFinished() {
SERIAL_PROTOCOLCHAR('.');
SERIAL_EOL();
}
else
else if (!read)
SERIAL_PROTOCOLLNPAIR(MSG_SD_WRITE_TO_FILE, job_recovery_file_name);
}
void CardReader::closeJobRecoveryFile() { jobRecoveryFile.close(); }
bool CardReader::jobRecoverFileExists() {
return jobRecoveryFile.open(&root, job_recovery_file_name, O_READ);
const bool exists = jobRecoveryFile.open(&root, job_recovery_file_name, O_READ);
if (exists) jobRecoveryFile.close();
return exists;
}
int16_t CardReader::saveJobRecoveryInfo() {
jobRecoveryFile.seekSet(0);
const int16_t ret = jobRecoveryFile.write(&job_recovery_info, sizeof(job_recovery_info));
if (ret == -1) SERIAL_PROTOCOLLNPGM("Power-loss file write failed.");
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
if (ret == -1) SERIAL_PROTOCOLLNPGM("Power-loss file write failed.");
#endif
return ret;
}
@@ -970,10 +973,15 @@ void CardReader::printingHasFinished() {
}
void CardReader::removeJobRecoveryFile() {
if (jobRecoveryFile.remove(&root, job_recovery_file_name))
SERIAL_PROTOCOLLNPGM("Power-loss file deleted.");
else
SERIAL_PROTOCOLLNPGM("Power-loss file delete failed.");
job_recovery_info.valid_head = job_recovery_info.valid_foot = job_recovery_commands_count = 0;
if (jobRecoverFileExists()) {
closefile();
removeFile(job_recovery_file_name);
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
SERIAL_PROTOCOLPGM("Power-loss file delete");
serialprintPGM(jobRecoverFileExists() ? PSTR(" failed.\n") : PSTR("d.\n"));
#endif
}
}
#endif // POWER_LOSS_RECOVERY
+1 -1
View File
@@ -117,7 +117,7 @@ public:
public:
bool saving, logging, sdprinting, cardOK, filenameIsDir;
char filename[FILENAME_LENGTH], longFilename[LONG_FILENAME_LENGTH];
int autostart_index;
int8_t autostart_index;
private:
SdFile root, workDir, workDirParents[MAX_DIR_DEPTH];
uint8_t workDirDepth;
+180 -119
View File
@@ -37,7 +37,7 @@
*/
// Change EEPROM version if the structure changes
#define EEPROM_VERSION "V54"
#define EEPROM_VERSION "V55"
#define EEPROM_OFFSET 100
// Check the integrity of data offsets.
@@ -97,16 +97,17 @@ typedef struct SettingsDataStruct {
//
uint8_t esteppers; // XYZE_N - XYZ
uint32_t planner_max_acceleration_mm_per_s2[XYZE_N], // M201 XYZE planner.max_acceleration_mm_per_s2[XYZE_N]
planner_min_segment_time_us; // M205 B planner.min_segment_time_us
float planner_axis_steps_per_mm[XYZE_N], // M92 XYZE planner.axis_steps_per_mm[XYZE_N]
planner_max_feedrate_mm_s[XYZE_N]; // M203 XYZE planner.max_feedrate_mm_s[XYZE_N]
uint32_t planner_max_acceleration_mm_per_s2[XYZE_N]; // M201 XYZE planner.max_acceleration_mm_per_s2[XYZE_N]
float planner_acceleration, // M204 P planner.acceleration
planner_max_feedrate_mm_s[XYZE_N], // M203 XYZE planner.max_feedrate_mm_s[XYZE_N]
planner_acceleration, // M204 P planner.acceleration
planner_retract_acceleration, // M204 R planner.retract_acceleration
planner_travel_acceleration, // M204 T planner.travel_acceleration
planner_min_feedrate_mm_s, // M205 S planner.min_feedrate_mm_s
planner_min_travel_feedrate_mm_s; // M205 T planner.min_travel_feedrate_mm_s
uint32_t planner_min_segment_time_us; // M205 B planner.min_segment_time_us
float planner_max_jerk[XYZE]; // M205 XYZE planner.max_jerk[XYZE]
planner_min_travel_feedrate_mm_s, // M205 T planner.min_travel_feedrate_mm_s
planner_max_jerk[XYZE], // M205 XYZE planner.max_jerk[XYZE]
planner_junction_deviation_mm; // M205 J planner.junction_deviation_mm
float home_offset[XYZ]; // M206 XYZ
@@ -318,6 +319,10 @@ void MarlinSettings::postprocess() {
fwretract.refresh_autoretract();
#endif
#if ENABLED(JUNCTION_DEVIATION) && ENABLED(LIN_ADVANCE)
planner.recalculate_max_e_jerk();
#endif
// Refresh steps_to_mm with the reciprocal of axis_steps_per_mm
// and init stepper.count[], planner.position[] with current_position
planner.refresh_positioning();
@@ -397,7 +402,7 @@ void MarlinSettings::postprocess() {
* M500 - Store Configuration
*/
bool MarlinSettings::save() {
float dummy = 0.0f;
float dummy = 0;
char ver[4] = "ERR";
uint16_t working_crc = 0;
@@ -416,17 +421,25 @@ void MarlinSettings::postprocess() {
const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ;
EEPROM_WRITE(esteppers);
EEPROM_WRITE(planner.max_acceleration_mm_per_s2);
EEPROM_WRITE(planner.min_segment_time_us);
EEPROM_WRITE(planner.axis_steps_per_mm);
EEPROM_WRITE(planner.max_feedrate_mm_s);
EEPROM_WRITE(planner.max_acceleration_mm_per_s2);
EEPROM_WRITE(planner.acceleration);
EEPROM_WRITE(planner.retract_acceleration);
EEPROM_WRITE(planner.travel_acceleration);
EEPROM_WRITE(planner.min_feedrate_mm_s);
EEPROM_WRITE(planner.min_travel_feedrate_mm_s);
EEPROM_WRITE(planner.min_segment_time_us);
EEPROM_WRITE(planner.max_jerk);
#if ENABLED(JUNCTION_DEVIATION)
const float planner_max_jerk[] = { float(DEFAULT_XJERK), float(DEFAULT_YJERK), float(DEFAULT_ZJERK), float(DEFAULT_EJERK) };
EEPROM_WRITE(planner_max_jerk);
EEPROM_WRITE(planner.junction_deviation_mm);
#else
EEPROM_WRITE(planner.max_jerk);
dummy = 0.02f;
EEPROM_WRITE(dummy);
#endif
_FIELD_TEST(home_offset);
@@ -468,7 +481,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(mesh_num_y);
EEPROM_WRITE(mbl.z_values);
#else // For disabled MBL write a default mesh
dummy = 0.0f;
dummy = 0;
const uint8_t mesh_num_x = 3, mesh_num_y = 3;
EEPROM_WRITE(dummy); // z_offset
EEPROM_WRITE(mesh_num_x);
@@ -490,7 +503,7 @@ void MarlinSettings::postprocess() {
#if ABL_PLANAR
EEPROM_WRITE(planner.bed_level_matrix);
#else
dummy = 0.0;
dummy = 0;
for (uint8_t q = 9; q--;) EEPROM_WRITE(dummy);
#endif
@@ -514,7 +527,7 @@ void MarlinSettings::postprocess() {
// For disabled Bilinear Grid write an empty 3x3 grid
const uint8_t grid_max_x = 3, grid_max_y = 3;
const int bilinear_start[2] = { 0 }, bilinear_grid_spacing[2] = { 0 };
dummy = 0.0f;
dummy = 0;
EEPROM_WRITE(grid_max_x);
EEPROM_WRITE(grid_max_y);
EEPROM_WRITE(bilinear_grid_spacing);
@@ -552,7 +565,7 @@ void MarlinSettings::postprocess() {
_FIELD_TEST(x_endstop_adj);
// Write dual endstops in X, Y, Z order. Unused = 0.0
dummy = 0.0f;
dummy = 0;
#if ENABLED(X_DUAL_ENDSTOPS)
EEPROM_WRITE(endstops.x_endstop_adj); // 1 float
#else
@@ -604,7 +617,7 @@ void MarlinSettings::postprocess() {
{
dummy = DUMMY_PID_VALUE; // When read, will not change the existing value
EEPROM_WRITE(dummy); // Kp
dummy = 0.0f;
dummy = 0;
for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy); // Ki, Kd, Kc
}
@@ -850,7 +863,7 @@ void MarlinSettings::postprocess() {
#if ENABLED(LIN_ADVANCE)
EEPROM_WRITE(planner.extruder_advance_K);
#else
dummy = 0.0f;
dummy = 0;
EEPROM_WRITE(dummy);
#endif
@@ -872,7 +885,7 @@ void MarlinSettings::postprocess() {
#if ENABLED(CNC_COORDINATE_SYSTEMS)
EEPROM_WRITE(coordinate_system); // 27 floats
#else
dummy = 0.0f;
dummy = 0;
for (uint8_t q = MAX_COORDINATE_SYSTEMS * XYZ; q--;) EEPROM_WRITE(dummy);
#endif
@@ -887,7 +900,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(planner.xz_skew_factor);
EEPROM_WRITE(planner.yz_skew_factor);
#else
dummy = 0.0f;
dummy = 0;
for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy);
#endif
@@ -907,7 +920,7 @@ void MarlinSettings::postprocess() {
EEPROM_WRITE(dummy);
}
#else
dummy = 0.0f;
dummy = 0;
for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_WRITE(dummy);
#endif
@@ -994,17 +1007,20 @@ void MarlinSettings::postprocess() {
// Get only the number of E stepper parameters previously stored
// Any steppers added later are set to their defaults
const float def1[] = DEFAULT_AXIS_STEPS_PER_UNIT, def2[] = DEFAULT_MAX_FEEDRATE;
const uint32_t def3[] = DEFAULT_MAX_ACCELERATION;
float tmp1[XYZ + esteppers], tmp2[XYZ + esteppers];
uint32_t tmp3[XYZ + esteppers];
EEPROM_READ(tmp1);
EEPROM_READ(tmp2);
EEPROM_READ(tmp3);
const uint32_t def1[] = DEFAULT_MAX_ACCELERATION;
const float def2[] = DEFAULT_AXIS_STEPS_PER_UNIT, def3[] = DEFAULT_MAX_FEEDRATE;
uint32_t tmp1[XYZ + esteppers];
EEPROM_READ(tmp1); // max_acceleration_mm_per_s2
EEPROM_READ(planner.min_segment_time_us);
float tmp2[XYZ + esteppers], tmp3[XYZ + esteppers];
EEPROM_READ(tmp2); // axis_steps_per_mm
EEPROM_READ(tmp3); // max_feedrate_mm_s
if (!validating) LOOP_XYZE_N(i) {
planner.axis_steps_per_mm[i] = i < XYZ + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1];
planner.max_feedrate_mm_s[i] = i < XYZ + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1];
planner.max_acceleration_mm_per_s2[i] = i < XYZ + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1];
planner.max_acceleration_mm_per_s2[i] = i < XYZ + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1];
planner.axis_steps_per_mm[i] = i < XYZ + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1];
planner.max_feedrate_mm_s[i] = i < XYZ + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1];
}
EEPROM_READ(planner.acceleration);
@@ -1012,8 +1028,14 @@ void MarlinSettings::postprocess() {
EEPROM_READ(planner.travel_acceleration);
EEPROM_READ(planner.min_feedrate_mm_s);
EEPROM_READ(planner.min_travel_feedrate_mm_s);
EEPROM_READ(planner.min_segment_time_us);
EEPROM_READ(planner.max_jerk);
#if ENABLED(JUNCTION_DEVIATION)
for (uint8_t q = 4; q--;) EEPROM_READ(dummy);
EEPROM_READ(planner.junction_deviation_mm);
#else
EEPROM_READ(planner.max_jerk);
EEPROM_READ(dummy);
#endif
//
// Home Offset (M206)
@@ -1596,7 +1618,7 @@ void MarlinSettings::postprocess() {
}
#endif
int16_t MarlinSettings::meshes_start_index() {
uint16_t MarlinSettings::meshes_start_index() {
return (datasize() + EEPROM_OFFSET + 32) & 0xFFF8; // Pad the end of configuration data so it can float up
// or down a little bit without disrupting the mesh data
}
@@ -1699,16 +1721,21 @@ void MarlinSettings::reset() {
planner.max_acceleration_mm_per_s2[i] = pgm_read_dword_near(&tmp3[i < COUNT(tmp3) ? i : COUNT(tmp3) - 1]);
}
planner.min_segment_time_us = DEFAULT_MINSEGMENTTIME;
planner.acceleration = DEFAULT_ACCELERATION;
planner.retract_acceleration = DEFAULT_RETRACT_ACCELERATION;
planner.travel_acceleration = DEFAULT_TRAVEL_ACCELERATION;
planner.min_feedrate_mm_s = DEFAULT_MINIMUMFEEDRATE;
planner.min_travel_feedrate_mm_s = DEFAULT_MINTRAVELFEEDRATE;
planner.min_segment_time_us = DEFAULT_MINSEGMENTTIME;
planner.max_jerk[X_AXIS] = DEFAULT_XJERK;
planner.max_jerk[Y_AXIS] = DEFAULT_YJERK;
planner.max_jerk[Z_AXIS] = DEFAULT_ZJERK;
planner.max_jerk[E_AXIS] = DEFAULT_EJERK;
#if ENABLED(JUNCTION_DEVIATION)
planner.junction_deviation_mm = float(JUNCTION_DEVIATION_MM);
#else
planner.max_jerk[X_AXIS] = DEFAULT_XJERK;
planner.max_jerk[Y_AXIS] = DEFAULT_YJERK;
planner.max_jerk[Z_AXIS] = DEFAULT_ZJERK;
planner.max_jerk[E_AXIS] = DEFAULT_EJERK;
#endif
#if HAS_HOME_OFFSET
ZERO(home_offset);
@@ -1804,7 +1831,7 @@ void MarlinSettings::reset() {
HOTEND_LOOP()
#endif
{
PID_PARAM(Kp, e) = DEFAULT_Kp;
PID_PARAM(Kp, e) = float(DEFAULT_Kp);
PID_PARAM(Ki, e) = scalePID_i(DEFAULT_Ki);
PID_PARAM(Kd, e) = scalePID_d(DEFAULT_Kd);
#if ENABLED(PID_EXTRUSION_SCALING)
@@ -1873,7 +1900,7 @@ void MarlinSettings::reset() {
#endif
#if ENABLED(ADVANCED_PAUSE_FEATURE)
for (uint8_t e = 0; e < E_STEPPERS; e++) {
for (uint8_t e = 0; e < EXTRUDERS; e++) {
filament_change_unload_length[e] = FILAMENT_CHANGE_UNLOAD_LENGTH;
filament_change_load_length[e] = FILAMENT_CHANGE_FAST_LOAD_LENGTH;
}
@@ -1892,12 +1919,12 @@ void MarlinSettings::reset() {
#define CONFIG_ECHO_START do{ if (!forReplay) SERIAL_ECHO_START(); }while(0)
#if HAS_TRINAMIC
void say_M906() { SERIAL_ECHOPGM(" M906 "); }
void say_M906() { SERIAL_ECHOPGM(" M906"); }
#if ENABLED(HYBRID_THRESHOLD)
void say_M913() { SERIAL_ECHOPGM(" M913 "); }
void say_M913() { SERIAL_ECHOPGM(" M913"); }
#endif
#if ENABLED(SENSORLESS_HOMING)
void say_M914() { SERIAL_ECHOPGM(" M914 "); }
void say_M914() { SERIAL_ECHOPGM(" M914"); }
#endif
#endif
@@ -2077,16 +2104,32 @@ void MarlinSettings::reset() {
if (!forReplay) {
CONFIG_ECHO_START;
SERIAL_ECHOLNPGM("Advanced: S<min_feedrate> T<min_travel_feedrate> B<min_segment_time_us> X<max_xy_jerk> Z<max_z_jerk> E<max_e_jerk>");
SERIAL_ECHOPGM("Advanced: B<min_segment_time_us> S<min_feedrate> T<min_travel_feedrate>");
#if ENABLED(JUNCTION_DEVIATION)
SERIAL_ECHOPGM(" J<junc_dev>");
#else
SERIAL_ECHOPGM(" X<max_x_jerk> Y<max_y_jerk> Z<max_z_jerk>");
#endif
#if DISABLED(JUNCTION_DEVIATION) || ENABLED(LIN_ADVANCE)
SERIAL_ECHOPGM(" E<max_e_jerk>");
#endif
SERIAL_EOL();
}
CONFIG_ECHO_START;
SERIAL_ECHOPAIR(" M205 S", LINEAR_UNIT(planner.min_feedrate_mm_s));
SERIAL_ECHOPAIR(" M205 B", LINEAR_UNIT(planner.min_segment_time_us));
SERIAL_ECHOPAIR(" S", LINEAR_UNIT(planner.min_feedrate_mm_s));
SERIAL_ECHOPAIR(" T", LINEAR_UNIT(planner.min_travel_feedrate_mm_s));
SERIAL_ECHOPAIR(" B", planner.min_segment_time_us);
SERIAL_ECHOPAIR(" X", LINEAR_UNIT(planner.max_jerk[X_AXIS]));
SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_jerk[Y_AXIS]));
SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_jerk[Z_AXIS]));
SERIAL_ECHOLNPAIR(" E", LINEAR_UNIT(planner.max_jerk[E_AXIS]));
#if ENABLED(JUNCTION_DEVIATION)
SERIAL_ECHOPAIR(" J", LINEAR_UNIT(planner.junction_deviation_mm));
#else
SERIAL_ECHOPAIR(" X", LINEAR_UNIT(planner.max_jerk[X_AXIS]));
SERIAL_ECHOPAIR(" Y", LINEAR_UNIT(planner.max_jerk[Y_AXIS]));
SERIAL_ECHOPAIR(" Z", LINEAR_UNIT(planner.max_jerk[Z_AXIS]));
SERIAL_ECHOPAIR(" E", LINEAR_UNIT(planner.max_jerk[E_AXIS]));
#endif
SERIAL_EOL();
#if HAS_M206_COMMAND
if (!forReplay) {
@@ -2161,7 +2204,7 @@ void MarlinSettings::reset() {
SERIAL_ECHOPAIR(" G29 S3 X", (int)px + 1);
SERIAL_ECHOPAIR(" Y", (int)py + 1);
SERIAL_ECHOPGM(" Z");
SERIAL_PROTOCOL_F(LINEAR_UNIT(mbl.z_values[px][py]), 5);
SERIAL_ECHO_F(LINEAR_UNIT(mbl.z_values[px][py]), 5);
SERIAL_EOL();
}
}
@@ -2185,10 +2228,10 @@ void MarlinSettings::reset() {
for (uint8_t py = 0; py < GRID_MAX_POINTS_Y; py++) {
for (uint8_t px = 0; px < GRID_MAX_POINTS_X; px++) {
CONFIG_ECHO_START;
SERIAL_ECHOPAIR(" G29 W I", (int)px + 1);
SERIAL_ECHOPAIR(" J", (int)py + 1);
SERIAL_ECHOPAIR(" G29 W I", (int)px);
SERIAL_ECHOPAIR(" J", (int)py);
SERIAL_ECHOPGM(" Z");
SERIAL_PROTOCOL_F(LINEAR_UNIT(z_values[px][py]), 5);
SERIAL_ECHO_F(LINEAR_UNIT(z_values[px][py]), 5);
SERIAL_EOL();
}
}
@@ -2392,49 +2435,56 @@ void MarlinSettings::reset() {
SERIAL_ECHOLNPGM("Stepper driver current:");
}
CONFIG_ECHO_START;
#if X_IS_TRINAMIC
#if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("X", stepperX.getCurrent());
#endif
#if X2_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("I1 X", stepperX2.getCurrent());
#if X_IS_TRINAMIC
SERIAL_ECHOPAIR(" X", stepperX.getCurrent());
#endif
#if Y_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("Y", stepperY.getCurrent());
#endif
#if Y2_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("I1 Y", stepperY2.getCurrent());
SERIAL_ECHOPAIR(" Y", stepperY.getCurrent());
#endif
#if Z_IS_TRINAMIC
SERIAL_ECHOPAIR(" Z", stepperZ.getCurrent());
#endif
#if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC
SERIAL_EOL();
#endif
#if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("Z", stepperZ.getCurrent());
SERIAL_ECHOPGM(" I1");
#endif
#if X2_IS_TRINAMIC
SERIAL_ECHOPAIR(" X", stepperX2.getCurrent());
#endif
#if Y2_IS_TRINAMIC
SERIAL_ECHOPAIR(" Y", stepperY2.getCurrent());
#endif
#if Z2_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("I1 Z", stepperZ2.getCurrent());
SERIAL_ECHOPAIR(" Z", stepperZ2.getCurrent());
#endif
#if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC
SERIAL_EOL();
#endif
#if E0_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("T0 E", stepperE0.getCurrent());
SERIAL_ECHOLNPAIR(" T0 E", stepperE0.getCurrent());
#endif
#if E_STEPPERS > 1 && E1_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("T1 E", stepperE1.getCurrent());
SERIAL_ECHOLNPAIR(" T1 E", stepperE1.getCurrent());
#endif
#if E_STEPPERS > 2 && E2_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("T2 E", stepperE2.getCurrent());
SERIAL_ECHOLNPAIR(" T2 E", stepperE2.getCurrent());
#endif
#if E_STEPPERS > 3 && E3_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("T3 E", stepperE3.getCurrent());
SERIAL_ECHOLNPAIR(" T3 E", stepperE3.getCurrent());
#endif
#if E_STEPPERS > 4 && E4_IS_TRINAMIC
say_M906();
SERIAL_ECHOLNPAIR("T4 E", stepperE4.getCurrent());
SERIAL_ECHOLNPAIR(" T4 E", stepperE4.getCurrent());
#endif
SERIAL_EOL();
@@ -2447,49 +2497,56 @@ void MarlinSettings::reset() {
SERIAL_ECHOLNPGM("Hybrid Threshold:");
}
CONFIG_ECHO_START;
#if X_IS_TRINAMIC
#if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("X", TMC_GET_PWMTHRS(X, X));
#endif
#if X2_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("I1 X", TMC_GET_PWMTHRS(X, X2));
#if X_IS_TRINAMIC
SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X));
#endif
#if Y_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("Y", TMC_GET_PWMTHRS(Y, Y));
#endif
#if Y2_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("I1 Y", TMC_GET_PWMTHRS(Y, Y2));
SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y));
#endif
#if Z_IS_TRINAMIC
SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z));
#endif
#if X_IS_TRINAMIC || Y_IS_TRINAMIC || Z_IS_TRINAMIC
SERIAL_EOL();
#endif
#if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("Z", TMC_GET_PWMTHRS(Z, Z));
SERIAL_ECHOPGM(" I1");
#endif
#if X2_IS_TRINAMIC
SERIAL_ECHOPAIR(" X", TMC_GET_PWMTHRS(X, X2));
#endif
#if Y2_IS_TRINAMIC
SERIAL_ECHOPAIR(" Y", TMC_GET_PWMTHRS(Y, Y2));
#endif
#if Z2_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("I1 Z", TMC_GET_PWMTHRS(Z, Z2));
SERIAL_ECHOPAIR(" Z", TMC_GET_PWMTHRS(Z, Z2));
#endif
#if X2_IS_TRINAMIC || Y2_IS_TRINAMIC || Z2_IS_TRINAMIC
SERIAL_EOL();
#endif
#if E0_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("T0 E", TMC_GET_PWMTHRS(E, E0));
SERIAL_ECHOLNPAIR(" T0 E", TMC_GET_PWMTHRS(E, E0));
#endif
#if E_STEPPERS > 1 && E1_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("T1 E", TMC_GET_PWMTHRS(E, E1));
SERIAL_ECHOLNPAIR(" T1 E", TMC_GET_PWMTHRS(E, E1));
#endif
#if E_STEPPERS > 2 && E2_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("T2 E", TMC_GET_PWMTHRS(E, E2));
SERIAL_ECHOLNPAIR(" T2 E", TMC_GET_PWMTHRS(E, E2));
#endif
#if E_STEPPERS > 3 && E3_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("T3 E", TMC_GET_PWMTHRS(E, E3));
SERIAL_ECHOLNPAIR(" T3 E", TMC_GET_PWMTHRS(E, E3));
#endif
#if E_STEPPERS > 4 && E4_IS_TRINAMIC
say_M913();
SERIAL_ECHOLNPAIR("T4 E", TMC_GET_PWMTHRS(E, E4));
SERIAL_ECHOLNPAIR(" T4 E", TMC_GET_PWMTHRS(E, E4));
#endif
SERIAL_EOL();
#endif // HYBRID_THRESHOLD
@@ -2503,38 +2560,42 @@ void MarlinSettings::reset() {
SERIAL_ECHOLNPGM("Sensorless homing threshold:");
}
CONFIG_ECHO_START;
#ifdef X_HOMING_SENSITIVITY
#if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS)
say_M914();
SERIAL_ECHOLNPAIR("X", stepperX.sgt());
#define HAS_X_SENSORLESS (defined(X_HOMING_SENSITIVITY) && (ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS)))
#define HAS_Y_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && (ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS)))
#define HAS_Z_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && (ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS)))
#if HAS_X_SENSORLESS || HAS_Y_SENSORLESS || HAS_Z_SENSORLESS
say_M914();
#if HAS_X_SENSORLESS
SERIAL_ECHOPAIR(" X", stepperX.sgt());
#endif
#if ENABLED(X2_IS_TMC2130)
say_M914();
SERIAL_ECHOLNPAIR("I1 X", stepperX2.sgt());
#if HAS_Y_SENSORLESS
SERIAL_ECHOPAIR(" Y", stepperY.sgt());
#endif
#if HAS_Z_SENSORLESS
SERIAL_ECHOPAIR(" Z", stepperZ.sgt());
#endif
SERIAL_EOL();
#endif
#ifdef Y_HOMING_SENSITIVITY
#if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS)
say_M914();
SERIAL_ECHOLNPAIR("Y", stepperY.sgt());
#define HAS_X2_SENSORLESS (defined(X_HOMING_SENSITIVITY) && ENABLED(X2_IS_TMC2130))
#define HAS_Y2_SENSORLESS (defined(Y_HOMING_SENSITIVITY) && ENABLED(Y2_IS_TMC2130))
#define HAS_Z2_SENSORLESS (defined(Z_HOMING_SENSITIVITY) && ENABLED(Z2_IS_TMC2130))
#if HAS_X2_SENSORLESS || HAS_Y2_SENSORLESS || HAS_Z2_SENSORLESS
say_M914();
SERIAL_ECHOPGM(" I1");
#if HAS_X2_SENSORLESS
SERIAL_ECHOPAIR(" X", stepperX2.sgt());
#endif
#if ENABLED(Y2_IS_TMC2130)
say_M914();
SERIAL_ECHOLNPAIR("I1 Y", stepperY2.sgt());
#if HAS_Y2_SENSORLESS
SERIAL_ECHOPAIR(" Y", stepperY2.sgt());
#endif
#if HAS_Z2_SENSORLESS
SERIAL_ECHOPAIR(" Z", stepperZ2.sgt());
#endif
SERIAL_EOL();
#endif
#ifdef Z_HOMING_SENSITIVITY
#if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS)
say_M914();
SERIAL_ECHOLNPAIR("Z", stepperZ.sgt());
#endif
#if ENABLED(Z2_IS_TMC2130)
say_M914();
SERIAL_ECHOLNPAIR("I1 Z", stepperZ2.sgt());
#endif
#endif
SERIAL_EOL();
#endif
#endif // SENSORLESS_HOMING
#endif // HAS_TRINAMIC
+4 -4
View File
@@ -53,8 +53,8 @@ class MarlinSettings {
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
// That can store is enabled
static int16_t meshes_start_index();
FORCE_INLINE static int16_t meshes_end_index() { return meshes_end; }
static uint16_t meshes_start_index();
FORCE_INLINE static uint16_t meshes_end_index() { return meshes_end; }
static uint16_t calc_num_meshes();
static int mesh_slot_offset(const int8_t slot);
static void store_mesh(const int8_t slot);
@@ -84,8 +84,8 @@ class MarlinSettings {
#if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
// That can store is enabled
static constexpr int16_t 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
static constexpr uint16_t 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
+1 -1
View File
@@ -89,7 +89,7 @@ static void i2c_send(const uint8_t channel, const byte v) {
// This is for the MCP4018 I2C based digipot
void digipot_i2c_set_current(uint8_t channel, float current) {
i2c_send(channel, current_to_wiper(MIN(MAX(current, 0.0f), float(DIGIPOT_A4988_MAX_CURRENT))));
i2c_send(channel, current_to_wiper(MIN(MAX(current, 0), float(DIGIPOT_A4988_MAX_CURRENT))));
}
void digipot_i2c_init() {
+1 -1
View File
@@ -50,7 +50,7 @@ static void i2c_send(const byte addr, const byte a, const byte b) {
// This is for the MCP4451 I2C based digipot
void digipot_i2c_set_current(uint8_t channel, float current) {
current = MIN((float) MAX(current, 0.0f), DIGIPOT_I2C_MAX_CURRENT);
current = MIN((float) MAX(current, 0), DIGIPOT_I2C_MAX_CURRENT);
// these addresses are specific to Azteeg X3 Pro, can be set to others,
// In this case first digipot is at address A0=0, A1= 0, second one is at A0=0, A1= 1
byte addr = 0x2C; // channel 0-3
+1 -1
View File
@@ -41,7 +41,7 @@
#include "macros.h"
// One ISR for all EXT-Interrupts
void endstop_ISR(void) { endstops.check_possible_change(); }
void endstop_ISR(void) { endstops.update(); }
/**
* Patch for pins_arduino.h (...\Arduino\hardware\arduino\avr\variants\mega\pins_arduino.h)
+131 -148
View File
@@ -35,12 +35,6 @@
#include "endstop_interrupts.h"
#endif
#if HAS_BED_PROBE
#define ENDSTOPS_ENABLED (enabled || z_probe_enabled)
#else
#define ENDSTOPS_ENABLED enabled
#endif
Endstops endstops;
// public:
@@ -49,9 +43,9 @@ bool Endstops::enabled, Endstops::enabled_globally; // Initialized by settings.l
volatile uint8_t Endstops::hit_state;
Endstops::esbits_t Endstops::live_state = 0;
#if ENABLED(ENDSTOP_NOISE_FILTER)
Endstops::esbits_t Endstops::old_live_state,
Endstops::validated_live_state;
Endstops::esbits_t Endstops::validated_live_state;
uint8_t Endstops::endstop_poll_count;
#endif
@@ -195,9 +189,6 @@ void Endstops::init() {
} // Endstops::init
// Called from ISR. A change was detected. Find out what happened!
void Endstops::check_possible_change() { if (ENDSTOPS_ENABLED) update(); }
// Called from ISR: Poll endstop state if required
void Endstops::poll() {
@@ -205,8 +196,10 @@ void Endstops::poll() {
run_monitor(); // report changes in endstop status
#endif
#if DISABLED(ENDSTOP_INTERRUPTS_FEATURE) || ENABLED(ENDSTOP_NOISE_FILTER)
if (ENDSTOPS_ENABLED) update();
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE) && ENABLED(ENDSTOP_NOISE_FILTER)
if (endstop_poll_count) update();
#elif DISABLED(ENDSTOP_INTERRUPTS_FEATURE) || ENABLED(ENDSTOP_NOISE_FILTER)
update();
#endif
}
@@ -214,7 +207,7 @@ void Endstops::enable_globally(const bool onoff) {
enabled_globally = enabled = onoff;
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
if (onoff) update(); // If enabling, update state now
update();
#endif
}
@@ -223,7 +216,7 @@ void Endstops::enable(const bool onoff) {
enabled = onoff;
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
if (onoff) update(); // If enabling, update state now
update();
#endif
}
@@ -232,17 +225,23 @@ void Endstops::not_homing() {
enabled = enabled_globally;
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
if (enabled) update(); // If enabling, update state now
update();
#endif
}
// If the last move failed to trigger an endstop, call kill
void Endstops::validate_homing_move() {
if (!trigger_state()) kill(PSTR(MSG_ERR_HOMING_FAILED));
hit_on_purpose();
}
// Enable / disable endstop z-probe checking
#if HAS_BED_PROBE
void Endstops::enable_z_probe(bool onoff) {
void Endstops::enable_z_probe(const bool onoff) {
z_probe_enabled = onoff;
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
if (enabled) update(); // If enabling, update state now
update();
#endif
}
#endif
@@ -369,10 +368,12 @@ void Endstops::M119() {
// Check endstops - Could be called from ISR!
void Endstops::update() {
// UPDATE_ENDSTOP_BIT: set the current endstop bits for an endstop to its status
#if DISABLED(ENDSTOP_NOISE_FILTER)
if (!abort_enabled()) return;
#endif
#define UPDATE_ENDSTOP_BIT(AXIS, MINMAX) SET_BIT_TO(live_state, _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_TO(DST, DST_BIT, TEST(DST, SRC_BIT))
#define COPY_LIVE_STATE(SRC_BIT, DST_BIT) SET_BIT_TO(live_state, DST_BIT, TEST(live_state, SRC_BIT))
#if ENABLED(G38_PROBE_TARGET) && PIN_EXISTS(Z_MIN_PROBE) && !(CORE_IS_XY || CORE_IS_XZ)
// If G38 command is active check Z_MIN_PROBE for ALL movement
@@ -407,162 +408,142 @@ void Endstops::update() {
#endif
/**
* Check and update endstops according to conditions
* Check and update endstops
*/
if (stepper.axis_is_moving(X_AXIS)) {
if (stepper.motor_direction(X_AXIS_HEAD)) { // -direction
#if HAS_X_MIN
#if ENABLED(X_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(X, MIN);
#if HAS_X2_MIN
UPDATE_ENDSTOP_BIT(X2, MIN);
#else
COPY_BIT(live_state, X_MIN, X2_MIN);
#endif
#else
if (X_MIN_TEST) UPDATE_ENDSTOP_BIT(X, MIN);
#endif
#if HAS_X_MIN
#if ENABLED(X_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(X, MIN);
#if HAS_X2_MIN
UPDATE_ENDSTOP_BIT(X2, MIN);
#else
COPY_LIVE_STATE(X_MIN, X2_MIN);
#endif
}
else { // +direction
#if HAS_X_MAX
#if ENABLED(X_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(X, MAX);
#if HAS_X2_MAX
UPDATE_ENDSTOP_BIT(X2, MAX);
#else
COPY_BIT(live_state, X_MAX, X2_MAX);
#endif
#else
if (X_MAX_TEST) UPDATE_ENDSTOP_BIT(X, MAX);
#endif
#endif
}
}
#else
UPDATE_ENDSTOP_BIT(X, MIN);
#endif
#endif
if (stepper.axis_is_moving(Y_AXIS)) {
if (stepper.motor_direction(Y_AXIS_HEAD)) { // -direction
#if HAS_Y_MIN
#if ENABLED(Y_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(Y, MIN);
#if HAS_Y2_MIN
UPDATE_ENDSTOP_BIT(Y2, MIN);
#else
COPY_BIT(live_state, Y_MIN, Y2_MIN);
#endif
#else
UPDATE_ENDSTOP_BIT(Y, MIN);
#endif
#if HAS_X_MAX
#if ENABLED(X_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(X, MAX);
#if HAS_X2_MAX
UPDATE_ENDSTOP_BIT(X2, MAX);
#else
COPY_LIVE_STATE(X_MAX, X2_MAX);
#endif
}
else { // +direction
#if HAS_Y_MAX
#if ENABLED(Y_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(Y, MAX);
#if HAS_Y2_MAX
UPDATE_ENDSTOP_BIT(Y2, MAX);
#else
COPY_BIT(live_state, Y_MAX, Y2_MAX);
#endif
#else
UPDATE_ENDSTOP_BIT(Y, MAX);
#endif
#endif
}
}
#else
UPDATE_ENDSTOP_BIT(X, MAX);
#endif
#endif
if (stepper.axis_is_moving(Z_AXIS)) {
if (stepper.motor_direction(Z_AXIS_HEAD)) { // Z -direction. Gantry down, bed up.
#if HAS_Z_MIN
#if ENABLED(Z_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(Z, MIN);
#if HAS_Z2_MIN
UPDATE_ENDSTOP_BIT(Z2, MIN);
#else
COPY_BIT(live_state, Z_MIN, Z2_MIN);
#endif
#else
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
if (z_probe_enabled) UPDATE_ENDSTOP_BIT(Z, MIN);
#else
UPDATE_ENDSTOP_BIT(Z, MIN);
#endif
#endif
#if HAS_Y_MIN
#if ENABLED(Y_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(Y, MIN);
#if HAS_Y2_MIN
UPDATE_ENDSTOP_BIT(Y2, MIN);
#else
COPY_LIVE_STATE(Y_MIN, Y2_MIN);
#endif
#else
UPDATE_ENDSTOP_BIT(Y, MIN);
#endif
#endif
// When closing the gap check the enabled probe
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
if (z_probe_enabled) UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
#if HAS_Y_MAX
#if ENABLED(Y_DUAL_ENDSTOPS)
UPDATE_ENDSTOP_BIT(Y, MAX);
#if HAS_Y2_MAX
UPDATE_ENDSTOP_BIT(Y2, MAX);
#else
COPY_LIVE_STATE(Y_MAX, Y2_MAX);
#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(live_state, Z_MAX, Z2_MAX);
#endif
// 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_BIT(Z, MAX);
#endif
#endif
}
}
#else
UPDATE_ENDSTOP_BIT(Y, MAX);
#endif
#endif
#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_LIVE_STATE(Z_MIN, Z2_MIN);
#endif
#elif ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
UPDATE_ENDSTOP_BIT(Z, MIN);
#elif Z_HOME_DIR < 0
UPDATE_ENDSTOP_BIT(Z, MIN);
#endif
#endif
// When closing the gap check the enabled probe
#if ENABLED(Z_MIN_PROBE_ENDSTOP)
UPDATE_ENDSTOP_BIT(Z, MIN_PROBE);
#endif
#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_LIVE_STATE(Z_MAX, Z2_MAX);
#endif
#elif DISABLED(Z_MIN_PROBE_ENDSTOP) || Z_MAX_PIN != Z_MIN_PROBE_PIN
// If this pin isn't the bed probe it's the Z endstop
UPDATE_ENDSTOP_BIT(Z, MAX);
#endif
#endif
// All endstops were updated.
#if ENABLED(ENDSTOP_NOISE_FILTER)
if (old_live_state != live_state) { // We detected a change. Reinit the timeout
/**
* Filtering out noise on endstops requires a delayed decision. Let's assume, due to noise,
* that 50% of endstop signal samples are good and 50% are bad (assuming normal distribution
* of random noise). Then the first sample has a 50% chance to be good or bad. The 2nd sample
* also has a 50% chance to be good or bad. The chances of 2 samples both being bad becomes
* 50% of 50%, or 25%. That was the previous implementation of Marlin endstop handling. It
* reduces chances of bad readings in half, at the cost of 1 extra sample period, but chances
* still exist. The only way to reduce them further is to increase the number of samples.
* To reduce the chance to 1% (1/128th) requires 7 samples (adding 7ms of delay).
*/
/**
* Filtering out noise on endstops requires a delayed decision. Let's assume, due to noise,
* that 50% of endstop signal samples are good and 50% are bad (assuming normal distribution
* of random noise). Then the first sample has a 50% chance to be good or bad. The 2nd sample
* also has a 50% chance to be good or bad. The chances of 2 samples both being bad becomes
* 50% of 50%, or 25%. That was the previous implementation of Marlin endstop handling. It
* reduces chances of bad readings in half, at the cost of 1 extra sample period, but chances
* still exist. The only way to reduce them further is to increase the number of samples.
* To reduce the chance to 1% (1/128th) requires 7 samples (adding 7ms of delay).
*/
static esbits_t old_live_state;
if (old_live_state != live_state) {
endstop_poll_count = 7;
old_live_state = live_state;
}
else if (endstop_poll_count && !--endstop_poll_count)
validated_live_state = live_state;
#else
// Lets accept the new endstop values as valid - We assume hardware filtering of lines
esbits_t validated_live_state = live_state;
if (!abort_enabled()) return;
#endif
// Endstop readings are validated in validated_live_state
// Test the current status of an endstop
#define TEST_ENDSTOP(ENDSTOP) (TEST(validated_live_state, ENDSTOP))
#define TEST_ENDSTOP(ENDSTOP) (TEST(state(), ENDSTOP))
// Record endstop was hit
#define _ENDSTOP_HIT(AXIS, MINMAX) SBI(hit_state, _ENDSTOP(AXIS, MINMAX))
// Call the endstop triggered routine for single endstops
#define PROCESS_ENDSTOP(AXIS,MINMAX) do { \
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
_ENDSTOP_HIT(AXIS, MINMAX); \
planner.endstop_triggered(_AXIS(AXIS)); \
} \
}while(0)
if (TEST_ENDSTOP(_ENDSTOP(AXIS, MINMAX))) { \
_ENDSTOP_HIT(AXIS, MINMAX); \
planner.endstop_triggered(_AXIS(AXIS)); \
} \
}while(0)
// Call the endstop triggered routine for single endstops
// Call the endstop triggered routine for dual endstops
#define PROCESS_DUAL_ENDSTOP(AXIS1, AXIS2, MINMAX) do { \
if (TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) || TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX))) { \
_ENDSTOP_HIT(AXIS1, MINMAX); \
const byte dual_hit = TEST_ENDSTOP(_ENDSTOP(AXIS1, MINMAX)) | (TEST_ENDSTOP(_ENDSTOP(AXIS2, MINMAX)) << 1); \
if (dual_hit) { \
_ENDSTOP_HIT(AXIS1, MINMAX); \
/* if not performing home or if both endstops were trigged during homing... */ \
if (!stepper.homing_dual_axis || dual_hit == 0x3) \
planner.endstop_triggered(_AXIS(AXIS1)); \
} \
}while(0)
} \
}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
@@ -627,6 +608,8 @@ void Endstops::update() {
#else
#if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
if (z_probe_enabled) PROCESS_ENDSTOP(Z, MIN);
#elif ENABLED(Z_MIN_PROBE_ENDSTOP)
if (!z_probe_enabled) PROCESS_ENDSTOP(Z, MIN);
#else
PROCESS_ENDSTOP(Z, MIN);
#endif
+26 -8
View File
@@ -69,9 +69,9 @@ class Endstops {
private:
static esbits_t live_state;
static volatile uint8_t hit_state; // Use X_MIN, Y_MIN, Z_MIN and Z_MIN_PROBE as BIT index
#if ENABLED(ENDSTOP_NOISE_FILTER)
static esbits_t old_live_state, // Old endstop value for debouncing and denoising
validated_live_state; // The validated (accepted as true) endstop bits
static esbits_t validated_live_state;
static uint8_t endstop_poll_count; // Countdown from threshold for polling
#endif
@@ -84,10 +84,15 @@ class Endstops {
static void init();
/**
* A change was detected or presumed to be in endstops pins. Find out what
* changed, if anything. Called from ISR contexts
* Are endstops or the probe set to abort the move?
*/
static void check_possible_change();
FORCE_INLINE static bool abort_enabled() {
return (enabled
#if HAS_BED_PROBE
|| z_probe_enabled
#endif
);
}
/**
* Periodic call to poll endstops if required. Called from temperature ISR
@@ -95,7 +100,9 @@ class Endstops {
static void poll();
/**
* Update the endstops bits from the pins
* Update endstops bits from the pins. Apply filtering to get a verified state.
* If abort_enabled() and moving towards a triggered switch, abort the current move.
* Called from ISR contexts.
*/
static void update();
@@ -107,7 +114,15 @@ class Endstops {
/**
* Get current endstops state
*/
FORCE_INLINE static esbits_t state() { return live_state; }
FORCE_INLINE static esbits_t state() {
return
#if ENABLED(ENDSTOP_NOISE_FILTER)
validated_live_state
#else
live_state
#endif
;
}
/**
* Report endstop hits to serial. Called from loop().
@@ -128,13 +143,16 @@ class Endstops {
// Disable / Enable endstops based on ENSTOPS_ONLY_FOR_HOMING and global enable
static void not_homing();
// If the last move failed to trigger an endstop, call kill
static void validate_homing_move();
// Clear endstops (i.e., they were hit intentionally) to suppress the report
FORCE_INLINE static void hit_on_purpose() { hit_state = 0; }
// Enable / disable endstop z-probe checking
#if HAS_BED_PROBE
static volatile bool z_probe_enabled;
static void enable_z_probe(bool onoff=true);
static void enable_z_probe(const bool onoff=true);
#endif
// Debugging of endstops
+2 -1
View File
@@ -153,7 +153,8 @@ void FWRetract::retract(const bool retracting
else {
// If a hop was done and Z hasn't changed, undo the Z hop
if (hop_amount) {
destination[Z_AXIS] -= hop_amount; // Move back down by the total hop amount
current_position[Z_AXIS] += hop_amount; // Restore the actual Z position
SYNC_PLAN_POSITION_KINEMATIC(); // Unspoof the position planner
feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS]; // Z feedrate to max
prepare_move_to_destination(); // Lower Z, set_current_to_destination
hop_amount = 0.0; // Clear the hop amount
+1 -2
View File
@@ -146,8 +146,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL Postupne")
#define MSG_LED_CONTROL _UxGT("LED Nastaveni")
#define MSG_LEDS_ON _UxGT("Svetla Zap")
#define MSG_LEDS_OFF _UxGT("Svetla Vyp")
#define MSG_LEDS _UxGT("Svetla")
#define MSG_LED_PRESETS _UxGT("Svetla Predvolby")
#define MSG_SET_LEDS_RED _UxGT("Cervena")
#define MSG_SET_LEDS_ORANGE _UxGT("Oranzova")
+1 -2
View File
@@ -149,8 +149,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL Postupně")
#define MSG_LED_CONTROL _UxGT("LED Nastavení")
#define MSG_LEDS_ON _UxGT("Světla Zap")
#define MSG_LEDS_OFF _UxGT("Světla Vyp")
#define MSG_LEDS _UxGT("Světla")
#define MSG_LED_PRESETS _UxGT("Světla Předvolby")
#define MSG_SET_LEDS_RED _UxGT("Červená")
#define MSG_SET_LEDS_ORANGE _UxGT("Oranžová")
+1 -2
View File
@@ -311,8 +311,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("Schrittweises UBL")
#define MSG_LED_CONTROL _UxGT("LED Kontrolle")
#define MSG_LEDS_ON _UxGT("Licht an")
#define MSG_LEDS_OFF _UxGT("Licht aus")
#define MSG_LEDS _UxGT("Licht")
#define MSG_LED_PRESETS _UxGT("Licht Einstellungen")
#define MSG_SET_LEDS_RED _UxGT("Rot")
#define MSG_SET_LEDS_ORANGE _UxGT("Orange")
+8 -5
View File
@@ -371,11 +371,8 @@
#ifndef MSG_LED_CONTROL
#define MSG_LED_CONTROL _UxGT("LED Control")
#endif
#ifndef MSG_LEDS_ON
#define MSG_LEDS_ON _UxGT("Lights On")
#endif
#ifndef MSG_LEDS_OFF
#define MSG_LEDS_OFF _UxGT("Lights Off")
#ifndef MSG_LEDS
#define MSG_LEDS _UxGT("Lights")
#endif
#ifndef MSG_LED_PRESETS
#define MSG_LED_PRESETS _UxGT("Light Presets")
@@ -540,6 +537,9 @@
#ifndef MSG_VE_JERK
#define MSG_VE_JERK _UxGT("Ve-jerk")
#endif
#ifndef MSG_JUNCTION_DEVIATION
#define MSG_JUNCTION_DEVIATION _UxGT("Junction Dev")
#endif
#ifndef MSG_VELOCITY
#define MSG_VELOCITY _UxGT("Velocity")
#endif
@@ -666,6 +666,9 @@
#ifndef MSG_STOP_PRINT
#define MSG_STOP_PRINT _UxGT("Stop print")
#endif
#ifndef MSG_POWER_LOSS_RECOVERY
#define MSG_POWER_LOSS_RECOVERY _UxGT("Power-Loss Recovery")
#endif
#ifndef MSG_CARD_MENU
#define MSG_CARD_MENU _UxGT("Print from SD")
#endif
+1 -2
View File
@@ -142,8 +142,7 @@
//#define MSG_UBL_Z_OFFSET_STOPPED _UxGT("Z-Offset Stopped")
//#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("Step-By-Step UBL")
#define MSG_LED_CONTROL _UxGT("LED ezarpenak")
#define MSG_LEDS_ON _UxGT("Argiak piztu")
#define MSG_LEDS_OFF _UxGT("Argiak itzali")
#define MSG_LEDS _UxGT("Argiak")
#define MSG_LED_PRESETS _UxGT("Argi aurrehautaketak")
#define MSG_SET_LEDS_RED _UxGT("Gorria")
#define MSG_SET_LEDS_ORANGE _UxGT("Laranja")
+1 -2
View File
@@ -144,8 +144,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL Pas a pas")
#define MSG_LED_CONTROL _UxGT("Controle LED")
#define MSG_LEDS_ON _UxGT("Lumiere ON")
#define MSG_LEDS_OFF _UxGT("Lumiere OFF")
#define MSG_LEDS _UxGT("Lumiere")
#define MSG_LED_PRESETS _UxGT("Preregl. LED.")
#define MSG_SET_LEDS_RED _UxGT("Rouge")
#define MSG_SET_LEDS_ORANGE _UxGT("Orange")
+1 -2
View File
@@ -145,8 +145,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL Pas à pas")
#define MSG_LED_CONTROL _UxGT("Contrôle LED")
#define MSG_LEDS_ON _UxGT("Lumière ON")
#define MSG_LEDS_OFF _UxGT("Lumière OFF")
#define MSG_LEDS _UxGT("Lumière")
#define MSG_LED_PRESETS _UxGT("Préregl. LED")
#define MSG_SET_LEDS_RED _UxGT("Rouge")
#define MSG_SET_LEDS_ORANGE _UxGT("Orange")
+3 -4
View File
@@ -56,13 +56,13 @@
#define MSG_HOME_OFFSETS_APPLIED _UxGT("Offset applicato")
#define MSG_SET_ORIGIN _UxGT("Imposta Origine")
#define MSG_PREHEAT_1 _UxGT("Preriscalda PLA")
#define MSG_PREHEAT_1_N _UxGT("Prerisc.PLA ")
#define MSG_PREHEAT_1_N _UxGT("Preris.PLA ")
#define MSG_PREHEAT_1_ALL MSG_PREHEAT_1_N _UxGT("Tutto")
#define MSG_PREHEAT_1_END MSG_PREHEAT_1_N _UxGT("Ugello")
#define MSG_PREHEAT_1_BEDONLY MSG_PREHEAT_1_N _UxGT("Piatto")
#define MSG_PREHEAT_1_SETTINGS MSG_PREHEAT_1_N _UxGT("conf")
#define MSG_PREHEAT_2 _UxGT("Preriscalda ABS")
#define MSG_PREHEAT_2_N _UxGT("Prerisc.ABS ")
#define MSG_PREHEAT_2_N _UxGT("Preris.ABS ")
#define MSG_PREHEAT_2_ALL MSG_PREHEAT_2_N _UxGT("Tutto")
#define MSG_PREHEAT_2_END MSG_PREHEAT_2_N _UxGT("Ugello")
#define MSG_PREHEAT_2_BEDONLY MSG_PREHEAT_2_N _UxGT("Piatto")
@@ -144,8 +144,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL passo passo")
#define MSG_LED_CONTROL _UxGT("Controllo LED")
#define MSG_LEDS_ON _UxGT("Luci On")
#define MSG_LEDS_OFF _UxGT("Luci Off")
#define MSG_LEDS _UxGT("Luci")
#define MSG_LED_PRESETS _UxGT("Preset luci")
#define MSG_SET_LEDS_RED _UxGT("Rosso")
#define MSG_SET_LEDS_ORANGE _UxGT("Arancione")
+1 -2
View File
@@ -145,8 +145,7 @@
#define MSG_UBL_Z_OFFSET_STOPPED _UxGT("Compensacao Z parou")
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL passo a passo")
#define MSG_LED_CONTROL _UxGT("Controle do LED")
#define MSG_LEDS_ON _UxGT("Luz Acesa")
#define MSG_LEDS_OFF _UxGT("Luz Apagada")
#define MSG_LEDS _UxGT("Luz")
#define MSG_LED_PRESETS _UxGT("Configuracao da Luz")
#define MSG_SET_LEDS_RED _UxGT("Luz Vermelha")
#define MSG_SET_LEDS_ORANGE _UxGT("Luz Laranja")
+1 -2
View File
@@ -147,8 +147,7 @@
#define MSG_UBL_Z_OFFSET_STOPPED _UxGT("Compensação Z parou")
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL passo a passo")
#define MSG_LED_CONTROL _UxGT("Controle do LED")
#define MSG_LEDS_ON _UxGT("Luz Acesa")
#define MSG_LEDS_OFF _UxGT("Luz Apagada")
#define MSG_LEDS _UxGT("Luz")
#define MSG_LED_PRESETS _UxGT("Configuração da Luz")
#define MSG_SET_LEDS_RED _UxGT("Luz Vermelha")
#define MSG_SET_LEDS_ORANGE _UxGT("Luz Laranja")
+1 -2
View File
@@ -145,8 +145,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("Пошаговое UBL")
#define MSG_LED_CONTROL _UxGT("Настройки LED")
#define MSG_LEDS_ON _UxGT("Включить подсветку")
#define MSG_LEDS_OFF _UxGT("Выключить подсветку")
#define MSG_LEDS _UxGT("Подсветку")
#define MSG_LED_PRESETS _UxGT("Предустановки света")
#define MSG_SET_LEDS_RED _UxGT("Красный свет")
#define MSG_SET_LEDS_ORANGE _UxGT("Оранжевый свет")
+6 -3
View File
@@ -43,6 +43,7 @@
#define MSG_SD_INSERTED _UxGT("Karta vložená")
#define MSG_SD_REMOVED _UxGT("Karta vybratá")
#define MSG_LCD_ENDSTOPS _UxGT("Endstopy") // max 8 znakov
#define MSG_LCD_SOFT_ENDSTOPS _UxGT("Soft.endstopy")
#define MSG_MAIN _UxGT("Hlavná ponuka")
#define MSG_AUTOSTART _UxGT("Autoštart")
#define MSG_DISABLE_STEPPERS _UxGT("Uvolniť motory")
@@ -148,8 +149,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("UBL Postupne")
#define MSG_LED_CONTROL _UxGT("Nastavenie LED")
#define MSG_LEDS_ON _UxGT("Zapnúť svetlo")
#define MSG_LEDS_OFF _UxGT("Vypnúť svetlo")
#define MSG_LEDS _UxGT("Svetlo")
#define MSG_LED_PRESETS _UxGT("Prednastavené farby")
#define MSG_SET_LEDS_RED _UxGT("Červená")
#define MSG_SET_LEDS_ORANGE _UxGT("Oranžová")
@@ -208,6 +208,7 @@
#define MSG_VC_JERK _UxGT("Vz-skok")
#endif
#define MSG_VE_JERK _UxGT("Ve-skok")
#define MSG_JUNCTION_DEVIATION _UxGT("Junction Dev")
#define MSG_VELOCITY _UxGT("Rýchlosť")
#define MSG_VMAX _UxGT("Vmax ")
#define MSG_VMIN _UxGT("Vmin")
@@ -255,8 +256,9 @@
#define MSG_CARD_MENU _UxGT("Tlačiť z SD")
#define MSG_NO_CARD _UxGT("Žiadna SD karta")
#define MSG_DWELL _UxGT("Spím...")
#define MSG_USERWAIT _UxGT("Čakám...")
#define MSG_USERWAIT _UxGT("Kliknutím pokrač.")
#define MSG_PRINT_PAUSED _UxGT("Tlač pozastavená")
#define MSG_PRINTING _UxGT("Tlačím...")
#define MSG_PRINT_ABORTED _UxGT("Tlač zrušená")
#define MSG_NO_MOVE _UxGT("Žiadny pohyb.")
#define MSG_KILLED _UxGT("PRERUŠENÉ. ")
@@ -318,6 +320,7 @@
#define MSG_DELTA_SETTINGS _UxGT("Delta nastavenia")
#define MSG_DELTA_AUTO_CALIBRATE _UxGT("Autokalibrácia")
#define MSG_DELTA_HEIGHT_CALIBRATE _UxGT("Nast.výšku delty")
#define MSG_DELTA_Z_OFFSET_CALIBRATE _UxGT("Offset sondy Z")
#define MSG_DELTA_DIAG_ROD _UxGT("Diag rameno")
#define MSG_DELTA_HEIGHT _UxGT("Výška")
#define MSG_DELTA_RADIUS _UxGT("Polomer")
+1 -2
View File
@@ -141,8 +141,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("一步步UBL") // "Step-By-Step UBL"
#define MSG_LED_CONTROL _UxGT("灯管控制") // "LED Control")
#define MSG_LEDS_ON _UxGT("灯") // "Lights On")
#define MSG_LEDS_OFF _UxGT("灯灭") // "Lights Off")
#define MSG_LEDS _UxGT("灯") // "Lights")
#define MSG_LED_PRESETS _UxGT("灯预置") // "Light Presets")
#define MSG_SET_LEDS_RED _UxGT("红") // "Red")
#define MSG_SET_LEDS_ORANGE _UxGT("橙") // "Orange")
+1 -2
View File
@@ -141,8 +141,7 @@
#define MSG_UBL_STEP_BY_STEP_MENU _UxGT("一步步UBL") // "Step-By-Step UBL"
#define MSG_LED_CONTROL _UxGT("灯管控制") // "LED Control")
#define MSG_LEDS_ON _UxGT("灯") // "Lights On")
#define MSG_LEDS_OFF _UxGT("灯灭") // "Lights Off")
#define MSG_LEDS _UxGT("灯") // "Lights")
#define MSG_LED_PRESETS _UxGT("灯预置") // "Light Presets")
#define MSG_SET_LEDS_RED _UxGT("红") // "Red")
#define MSG_SET_LEDS_ORANGE _UxGT("橙") // "Orange")
+20 -20
View File
@@ -81,15 +81,14 @@
#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1)))
// Macros for maths shortcuts
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#define RADIANS(d) ((d)*M_PI/180.0)
#define DEGREES(r) ((r)*180.0/M_PI)
#undef M_PI
#define M_PI 3.14159265358979323846f
#define RADIANS(d) ((d)*M_PI/180.0f)
#define DEGREES(r) ((r)*180.0f/M_PI)
#define HYPOT2(x,y) (sq(x)+sq(y))
#define CIRCLE_AREA(R) (M_PI * sq(R))
#define CIRCLE_CIRC(R) (2.0 * M_PI * (R))
#define CIRCLE_AREA(R) (M_PI * sq(float(R)))
#define CIRCLE_CIRC(R) (2 * M_PI * (float(R)))
#define SIGN(a) ((a>0)-(a<0))
#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1)))
@@ -162,8 +161,8 @@
#define PENDING(NOW,SOON) ((long)(NOW-(SOON))<0)
#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON))
#define MMM_TO_MMS(MM_M) ((MM_M)/60.0)
#define MMS_TO_MMM(MM_S) ((MM_S)*60.0)
#define MMM_TO_MMS(MM_M) ((MM_M)/60.0f)
#define MMS_TO_MMM(MM_S) ((MM_S)*60.0f)
#define NOOP do{} while(0)
@@ -212,23 +211,24 @@
#define MAX4(a, b, c, d) MAX(MAX3(a, b, c), d)
#define MAX5(a, b, c, d, e) MAX(MAX4(a, b, c, d), e)
#define UNEAR_ZERO(x) ((x) < 0.000001)
#define NEAR_ZERO(x) WITHIN(x, -0.000001, 0.000001)
#define UNEAR_ZERO(x) ((x) < 0.000001f)
#define NEAR_ZERO(x) WITHIN(x, -0.000001f, 0.000001f)
#define NEAR(x,y) NEAR_ZERO((x)-(y))
#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0.0 : 1.0 / (x))
#define FIXFLOAT(f) (f + (f < 0.0 ? -0.00005 : 0.00005))
#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0.0f : 1.0f / (x))
#define FIXFLOAT(f) (f + (f < 0.0f ? -0.00005f : 0.00005f))
//
// Maths macros that can be overridden by HAL
//
#define ATAN2(y, x) atan2(y, x)
#define POW(x, y) pow(x, y)
#define SQRT(x) sqrt(x)
#define CEIL(x) ceil(x)
#define FLOOR(x) floor(x)
#define LROUND(x) lround(x)
#define FMOD(x, y) fmod(x, y)
#define ATAN2(y, x) atan2f(y, x)
#define POW(x, y) powf(x, y)
#define SQRT(x) sqrtf(x)
#define RSQRT(x) (1 / sqrtf(x))
#define CEIL(x) ceilf(x)
#define FLOOR(x) floorf(x)
#define LROUND(x) lroundf(x)
#define FMOD(x, y) fmodf(x, y)
#define HYPOT(x,y) SQRT(HYPOT2(x,y))
#endif //__MACROS_H
+4 -4
View File
@@ -72,22 +72,22 @@ public:
}
static int8_t cell_index_x(const float &x) {
int8_t cx = (x - (MESH_MIN_X)) * (1.0 / (MESH_X_DIST));
int8_t cx = (x - (MESH_MIN_X)) * (1.0f / (MESH_X_DIST));
return constrain(cx, 0, (GRID_MAX_POINTS_X) - 2);
}
static int8_t cell_index_y(const float &y) {
int8_t cy = (y - (MESH_MIN_Y)) * (1.0 / (MESH_Y_DIST));
int8_t cy = (y - (MESH_MIN_Y)) * (1.0f / (MESH_Y_DIST));
return constrain(cy, 0, (GRID_MAX_POINTS_Y) - 2);
}
static int8_t probe_index_x(const float &x) {
int8_t px = (x - (MESH_MIN_X) + 0.5 * (MESH_X_DIST)) * (1.0 / (MESH_X_DIST));
int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * (1.0f / (MESH_X_DIST));
return WITHIN(px, 0, GRID_MAX_POINTS_X - 1) ? px : -1;
}
static int8_t probe_index_y(const float &y) {
int8_t py = (y - (MESH_MIN_Y) + 0.5 * (MESH_Y_DIST)) * (1.0 / (MESH_Y_DIST));
int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * (1.0f / (MESH_Y_DIST));
return WITHIN(py, 0, GRID_MAX_POINTS_Y - 1) ? py : -1;
}
+5 -3
View File
@@ -39,6 +39,8 @@
#include "serial.h"
#endif
#define strtof strtod
/**
* GCode parser
*
@@ -194,15 +196,15 @@ public:
if (c == '\0' || c == ' ') break;
if (c == 'E' || c == 'e') {
*e = '\0';
const float ret = strtod(value_ptr, NULL);
const float ret = strtof(value_ptr, NULL);
*e = c;
return ret;
}
++e;
}
return strtod(value_ptr, NULL);
return strtof(value_ptr, NULL);
}
return 0.0;
return 0;
}
// Code value as a long or ulong
+3 -1
View File
@@ -132,7 +132,9 @@
#define HEATER_0_PIN 15 // C5
#define HEATER_BED_PIN 14 // C4
#define FAN_PIN 16 // C6 PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A
#endif
//
// Misc. Functions
+4 -1
View File
@@ -133,7 +133,10 @@
//
#define HEATER_0_PIN 13 // (extruder)
#define HEATER_BED_PIN 12 // (bed)
#define FAN_PIN 4
#ifndef FAN_PIN
#define FAN_PIN 4
#endif
//
// Misc. Functions
+15 -11
View File
@@ -24,22 +24,29 @@
* AZTEEG_X3_PRO (Arduino Mega) pin assignments
*/
#ifndef __AVR_ATmega2560__
#error "Oops! Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu."
#endif
#if HOTENDS > 5 || E_STEPPERS > 5
#error "Azteeg X3 Pro supports up to 5 hotends / E-steppers. Comment out this line to continue."
#endif
#if ENABLED(CASE_LIGHT_ENABLE) && !PIN_EXISTS(CASE_LIGHT)
#define CASE_LIGHT_PIN 44 // Define before RAMPS pins include
#endif
#define BOARD_NAME "Azteeg X3 Pro"
#include "pins_RAMPS.h"
#ifndef __AVR_ATmega2560__
#error "Oops! Make sure you have 'Arduino Mega 2560' selected from the 'Tools -> Boards' menu."
//
// RAMPS pins overrides
//
#if ENABLED(CASE_LIGHT_ENABLE) && !PIN_EXISTS(CASE_LIGHT)
#define CASE_LIGHT_PIN 44
#endif
#ifndef FAN_PIN
#define FAN_PIN 6
#endif
#include "pins_RAMPS.h"
// DIGIPOT slave addresses
#define DIGIPOT_I2C_ADDRESS_A 0x2C // unshifted slave address for first DIGIPOT 0x2C (0x58 <- 0x2C << 1)
#define DIGIPOT_I2C_ADDRESS_B 0x2E // unshifted slave address for second DIGIPOT 0x2E (0x5C <- 0x2E << 1)
@@ -116,9 +123,6 @@
#define HEATER_6_PIN 6
#define HEATER_7_PIN 11
#undef FAN_PIN
#define FAN_PIN 6 // Part Cooling System
#ifndef CONTROLLER_FAN_PIN
#define CONTROLLER_FAN_PIN 4 // Pin used for the fan to cool motherboard (-1 to disable)
#endif
+3 -1
View File
@@ -115,7 +115,9 @@
#define HEATER_0_PIN 32 // A4 Extruder
#define HEATER_BED_PIN 18 // E6 Bed
#define FAN_PIN 31 // A3 Fan
#ifndef FAN_PIN
#define FAN_PIN 31 // A3 Fan
#endif
//
// Misc. Functions
+3 -1
View File
@@ -125,7 +125,9 @@
//
#define HEATER_0_PIN 27 // B7
#define HEATER_BED_PIN 26 // B6 Bed
#define FAN_PIN 16 // C6 Fan, PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 Fan, PWM3A
#endif
//
// Misc. Functions
+2 -2
View File
@@ -69,8 +69,8 @@
//
// Heaters / Fans
//
#define HEATER_0_PIN 19 // EXTRUDER 1
#define HEATER_1_PIN 23 // EXTRUDER 2
#define HEATER_0_PIN 19 // EXTRUDER 1
#define HEATER_1_PIN 23 // EXTRUDER 2
#define HEATER_BED_PIN 22
//
+27 -24
View File
@@ -31,6 +31,7 @@
#endif
#define BOARD_NAME "Cheaptronic v2.0"
//
// Limit Switches
//
@@ -80,10 +81,32 @@
//
// Heaters / Fans
//
#define HEATER_0_PIN 6
#define HEATER_1_PIN 7
#define HEATER_2_PIN 8
#define HEATER_BED_PIN 9
#define HEATER_0_PIN 6
#define HEATER_1_PIN 7
#define HEATER_2_PIN 8
#define HEATER_BED_PIN 9
#ifndef FAN_PIN
#define FAN_PIN 3
#endif
#define FAN2_PIN 58 // additional fan or light control output
//
// Other board specific pins
//
#ifndef FIL_RUNOUT_PIN
#define FIL_RUNOUT_PIN 37 // board input labeled as F-DET
#endif
#define Z_MIN_PROBE_PIN 36 // additional external board input labeled as E-SENS (should be used for Z-probe)
#define LED_PIN 13
#define SPINDLE_ENABLE_PIN 4 // additional PWM pin 1 at JP1 connector - should be used for laser control too
#define EXT_2 5 // additional PWM pin 2 at JP1 connector
#define EXT_3 2 // additional PWM pin 3 at JP1 connector
#define PS_ON_PIN 45
#define KILL_PIN 46
#ifndef FILWIDTH_PIN
#define FILWIDTH_PIN 11 // shared with TEMP_3 analog input
#endif
//
// LCD
@@ -105,23 +128,3 @@
#define BTN_EN1 11
#define BTN_EN2 12
#define BTN_ENC 43
//
// Other board specific pins
//
#ifndef FIL_RUNOUT_PIN
#define FIL_RUNOUT_PIN 37 // board input labeled as F-DET
#endif
#define Z_MIN_PROBE_PIN 36 // additional external board input labeled as E-SENS (should be used for Z-probe)
#define LED_PIN 13
#define SPINDLE_ENABLE_PIN 4 // additional PWM pin 1 at JP1 connector - should be used for laser control too
#define EXT_2 5 // additional PWM pin 2 at JP1 connector
#define EXT_3 2 // additional PWM pin 3 at JP1 connector
#define FAN_PIN 3
#define FAN2_PIN 58 // additional fan or light control output
#define PS_ON_PIN 45
#define KILL_PIN 46
#ifndef FILWIDTH_PIN
#define FILWIDTH_PIN 11 // shared with TEMP_3 analog input
#endif
+3 -1
View File
@@ -65,7 +65,9 @@
#define HEATER_3_PIN 46
#define HEATER_BED_PIN 2
//#define FAN_PIN 7 // common PWM pin for all tools
#ifndef FAN_PIN
//#define FAN_PIN 7 // common PWM pin for all tools
#endif
#define ORIG_E0_AUTO_FAN_PIN 7
#define ORIG_E1_AUTO_FAN_PIN 7
+4 -2
View File
@@ -65,7 +65,9 @@
#define HEATER_3_PIN 3
#define HEATER_BED_PIN 24
#define FAN_PIN 5 // 5 is PWMtool3 -> 7 is common PWM pin for all tools
#ifndef FAN_PIN
#define FAN_PIN 5 // 5 is PWMtool3 -> 7 is common PWM pin for all tools
#endif
#define ORIG_E0_AUTO_FAN_PIN 7
#define ORIG_E1_AUTO_FAN_PIN 7
@@ -124,4 +126,4 @@
//#define UI2 37
#define STAT_LED_BLUE_PIN -1
#define STAT_LED_RED_PIN 10 // TOOL_0_PWM_PIN
#define STAT_LED_RED_PIN 10 // TOOL_0_PWM_PIN
+3 -1
View File
@@ -117,7 +117,9 @@
#define HEATER_0_PIN 3
#define HEATER_BED_PIN 4
#define FAN_PIN 8
#ifndef FAN_PIN
#define FAN_PIN 8
#endif
#define FAN1_PIN 6
//
+3 -1
View File
@@ -134,7 +134,9 @@
#define HEATER_0_PIN 3
#define HEATER_BED_PIN 4
#define FAN_PIN 8
#ifndef FAN_PIN
#define FAN_PIN 8
#endif
#define FAN1_PIN 6
//
+3 -1
View File
@@ -90,7 +90,9 @@
#define HEATER_2_PIN 17 // 12V PWM3
#define HEATER_BED_PIN 44 // DOUBLE 12V PWM
#define FAN_PIN 16 // 5V PWM
#ifndef FAN_PIN
#define FAN_PIN 16 // 5V PWM
#endif
//
// Misc. Functions
+3 -4
View File
@@ -68,11 +68,11 @@
//
#define X_STEP_PIN 15
#define X_DIR_PIN 18
#define X_ENABLE_PIN 24 // actually uses Y_enable_pin
#define X_ENABLE_PIN 24 // actually uses Y_enable_pin
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_ENABLE_PIN 24 // shared with X_enable_pin
#define Y_ENABLE_PIN 24 // shared with X_enable_pin
#define Z_STEP_PIN 27
#define Z_DIR_PIN 28
@@ -95,7 +95,6 @@
//
// Misc. Functions
//
#define PS_ON_PIN 14 // Alex, does this work on the card?
#define PS_ON_PIN 14 // Alex, does this work on the card?
// Alex extras from Gen3+
+2 -2
View File
@@ -112,8 +112,8 @@
#define HEATER_0_PIN 4
#define HEATER_BED_PIN 3
#if GEN7_VERSION < 13 // Gen7 v1.3 removed the fan pin
#define FAN_PIN 31
#if !defined(FAN_PIN) && GEN7_VERSION < 13 // Gen7 v1.3 removed the fan pin
#define FAN_PIN 31
#endif
//
+3 -1
View File
@@ -81,7 +81,9 @@
#define HEATER_0_PIN 2
#define HEATER_1_PIN 3
#define HEATER_BED_PIN 4
#define FAN_PIN 7
#ifndef FAN_PIN
#define FAN_PIN 7
#endif
//
// Misc. Functions
+14 -14
View File
@@ -47,21 +47,21 @@
#define X_DIR_PIN 63
#define X_ENABLE_PIN 29
#define Y_STEP_PIN 14 // A6
#define Y_DIR_PIN 15 // A0
#define Y_STEP_PIN 14 // A6
#define Y_DIR_PIN 15 // A0
#define Y_ENABLE_PIN 39
#define Z_STEP_PIN 31 // A2
#define Z_DIR_PIN 32 // A6
#define Z_ENABLE_PIN 30 // A1
#define Z_STEP_PIN 31 // A2
#define Z_DIR_PIN 32 // A6
#define Z_ENABLE_PIN 30 // A1
#define E0_STEP_PIN 34 // 34
#define E0_DIR_PIN 35 // 35
#define E0_ENABLE_PIN 33 // 33
#define E0_STEP_PIN 34 // 34
#define E0_DIR_PIN 35 // 35
#define E0_ENABLE_PIN 33 // 33
#define E1_STEP_PIN 37 // 37
#define E1_DIR_PIN 40 // 40
#define E1_ENABLE_PIN 36 // 36
#define E1_STEP_PIN 37 // 37
#define E1_DIR_PIN 40 // 40
#define E1_ENABLE_PIN 36 // 36
//
// Temperature Sensors
@@ -74,9 +74,9 @@
// Heaters / Fans
//
#define HEATER_0_PIN 9
#define HEATER_1_PIN 8 // 12
#define HEATER_2_PIN 11 // 13
#define HEATER_BED_PIN 10 // 14/15
#define HEATER_1_PIN 8 // 12
#define HEATER_2_PIN 11 // 13
#define HEATER_BED_PIN 10 // 14/15
#define FAN_PIN 7
+12 -10
View File
@@ -62,17 +62,17 @@
//
// Steppers
//
#define X_STEP_PIN 62 // A8
#define X_DIR_PIN 63 // A9
#define X_ENABLE_PIN 61 // A7
#define X_STEP_PIN 62 // A8
#define X_DIR_PIN 63 // A9
#define X_ENABLE_PIN 61 // A7
#define Y_STEP_PIN 65 // A11
#define Y_DIR_PIN 66 // A12
#define Y_ENABLE_PIN 64 // A10
#define Y_STEP_PIN 65 // A11
#define Y_DIR_PIN 66 // A12
#define Y_ENABLE_PIN 64 // A10
#define Z_STEP_PIN 68 // A14
#define Z_DIR_PIN 69 // A15
#define Z_ENABLE_PIN 67 // A13
#define Z_STEP_PIN 68 // A14
#define Z_DIR_PIN 69 // A15
#define Z_ENABLE_PIN 67 // A13
#define E0_STEP_PIN 23
#define E0_DIR_PIN 24
@@ -112,7 +112,9 @@
#define HEATER_1_PIN 34
#define HEATER_BED_PIN 28
#define FAN_PIN 39
#ifndef FAN_PIN
#define FAN_PIN 39
#endif
#define FAN1_PIN 35
#define FAN2_PIN 36
+8 -6
View File
@@ -53,13 +53,13 @@
#define X_DIR_PIN 28
#define X_ENABLE_PIN 24
#define Y_STEP_PIN 60 // A6
#define Y_DIR_PIN 61 // A7
#define Y_STEP_PIN 60 // A6
#define Y_DIR_PIN 61 // A7
#define Y_ENABLE_PIN 22
#define Z_STEP_PIN 54 // A0
#define Z_DIR_PIN 55 // A1
#define Z_ENABLE_PIN 56 // A2
#define Z_STEP_PIN 54 // A0
#define Z_DIR_PIN 55 // A1
#define Z_ENABLE_PIN 56 // A2
#define E0_STEP_PIN 31
#define E0_DIR_PIN 32
@@ -87,7 +87,9 @@
#define HEATER_1_PIN 8
#define HEATER_BED_PIN 10
#define FAN_PIN 7 // IO pin. Buffer needed
#ifndef FAN_PIN
#define FAN_PIN 7 // IO pin. Buffer needed
#endif
//
// Misc. Functions
+3 -1
View File
@@ -101,7 +101,9 @@
#define HEATER_1_PIN 8
#define HEATER_BED_PIN 10
#define FAN_PIN 7
#ifndef FAN_PIN
#define FAN_PIN 7
#endif
#define FAN1_PIN 6
//
+3 -1
View File
@@ -118,7 +118,9 @@
#define HEATER_2_PIN 8
#define HEATER_BED_PIN 10
#define FAN_PIN 6
#ifndef FAN_PIN
#define FAN_PIN 6
#endif
#define FAN1_PIN 7
//
+53 -54
View File
@@ -134,14 +134,14 @@
// 2 E4 CS2
// 78 E2 SCK
//
#define THERMO_SCK_PIN 78 // E2
#define THERMO_DO_PIN 3 // E5
#define THERMO_CS1 5 // E3
#define THERMO_CS2 2 // E4
#define THERMO_SCK_PIN 78 // E2
#define THERMO_DO_PIN 3 // E5
#define THERMO_CS1 5 // E3
#define THERMO_CS2 2 // E4
#define MAX6675_SS THERMO_CS1
#define MAX6675_SCK_PIN THERMO_SCK_PIN
#define MAX6675_DO_PIN THERMO_DO_PIN
#define MAX6675_SS THERMO_CS1
#define MAX6675_SCK_PIN THERMO_SCK_PIN
#define MAX6675_DO_PIN THERMO_DO_PIN
//
// Augmentation for auto-assigning plugs
//
@@ -149,10 +149,10 @@
// 2 extruders or 1 extruder and a heated bed.
// With no heated bed, an additional 24V fan is possible.
//
#define MOSFET_A_PIN 6 // H3
#define MOSFET_B_PIN 11 // B5 - Rev A of this file had this pin assigned to 9
#define MOSFET_C_PIN 45 // L4
#define MOSFET_D_PIN 44 // L5
#define MOSFET_A_PIN 6 // H3
#define MOSFET_B_PIN 11 // B5 - Rev A of this file had this pin assigned to 9
#define MOSFET_C_PIN 45 // L4
#define MOSFET_D_PIN 44 // L5
#if HOTENDS > 1
#if TEMP_SENSOR_BED
@@ -172,23 +172,24 @@
#define HEATER_0_PIN MOSFET_A_PIN
#if ENABLED(IS_EFB) // Hotend, Fan, Bed
#define FAN_PIN MOSFET_B_PIN
#define HEATER_BED_PIN MOSFET_C_PIN
#define HEATER_BED_PIN MOSFET_C_PIN
#elif ENABLED(IS_EEF) // Hotend, Hotend, Fan
#define HEATER_1_PIN MOSFET_B_PIN
#define FAN_PIN MOSFET_C_PIN
#define HEATER_1_PIN MOSFET_B_PIN
#elif ENABLED(IS_EEB) // Hotend, Hotend, Bed
#define HEATER_1_PIN MOSFET_B_PIN
#define HEATER_BED_PIN MOSFET_C_PIN
#define HEATER_1_PIN MOSFET_B_PIN
#define HEATER_BED_PIN MOSFET_C_PIN
#elif ENABLED(IS_EFF) // Hotend, Fan, Fan
#define FAN_PIN MOSFET_B_PIN
#define FAN1_PIN MOSFET_C_PIN
#elif ENABLED(IS_SF) // Spindle, Fan
#define FAN_PIN MOSFET_C_PIN
#define FAN1_PIN MOSFET_C_PIN
#endif
#ifndef FAN_PIN
#define FAN_PIN MOSFET_D_PIN
#if ENABLED(IS_EFB) || ENABLED(IS_EFF) // Hotend, Fan, Bed or Hotend, Fan, Fan
#define FAN_PIN MOSFET_B_PIN
#elif ENABLED(IS_EEF) || ENABLED(IS_SF) // Hotend, Hotend, Fan or Spindle, Fan
#define FAN_PIN MOSFET_C_PIN
#else
#define FAN_PIN MOSFET_D_PIN
#endif
#endif
//
@@ -200,37 +201,37 @@
//
// Misc. Functions
//
#define LED_PIN 13 // B7
#define CUTOFF_RESET_PIN 16 // H1
#define CUTOFF_TEST_PIN 17 // H0
#define CASE_LIGHT_PIN 44 // L5 MUST BE HARDWARE PWM
#define LED_PIN 13 // B7
#define CUTOFF_RESET_PIN 16 // H1
#define CUTOFF_TEST_PIN 17 // H0
#define CASE_LIGHT_PIN 44 // L5 MUST BE HARDWARE PWM
//
// LCD / Controller
//
#ifdef REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER
#define LCD_PINS_RS 33 // C4: LCD-STROBE
#define LCD_PINS_ENABLE 72 // J2: LEFT
#define LCD_PINS_D4 35 // C2: LCD-CLK
#define LCD_PINS_D5 32 // C5: RLED
#define LCD_PINS_D6 34 // C3: LCD-DATA
#define LCD_PINS_D7 31 // C6: GLED
#define LCD_PINS_RS 33 // C4: LCD-STROBE
#define LCD_PINS_ENABLE 72 // J2: LEFT
#define LCD_PINS_D4 35 // C2: LCD-CLK
#define LCD_PINS_D5 32 // C5: RLED
#define LCD_PINS_D6 34 // C3: LCD-DATA
#define LCD_PINS_D7 31 // C6: GLED
#define BTN_EN2 75 // J4, UP
#define BTN_EN1 73 // J3, DOWN
#define BTN_EN2 75 // J4, UP
#define BTN_EN1 73 // J3, DOWN
//STOP button connected as KILL_PIN
#define KILL_PIN 14 // J1, RIGHT
#define KILL_PIN 14 // J1, RIGHT
//KILL - not connected
#define BEEPER_PIN 8 // H5, SD_WP
#define BEEPER_PIN 8 // H5, SD_WP
#define BTN_CENTER 15 // J0
#define BTN_ENC BTN_CENTER
#define BTN_CENTER 15 // J0
#define BTN_ENC BTN_CENTER
//on board leds
#define STAT_LED_RED_LED SERVO0_PIN // C1 (1280-EX1, DEBUG2)
#define STAT_LED_BLUE_PIN SERVO1_PIN // C0 (1280-EX2, DEBUG3)
#define STAT_LED_RED_LED SERVO0_PIN // C1 (1280-EX1, DEBUG2)
#define STAT_LED_BLUE_PIN SERVO1_PIN // C0 (1280-EX2, DEBUG3)
#else
// Replicator uses a 3-wire SR controller with HD44780
@@ -238,18 +239,18 @@
//
#define SAV_3DLCD
#define SR_DATA_PIN 34 // C3
#define SR_CLK_PIN 35 // C2
#define SR_STROBE_PIN 33 // C4
#define SR_DATA_PIN 34 // C3
#define SR_CLK_PIN 35 // C2
#define SR_STROBE_PIN 33 // C4
#define BTN_UP 75 // J4
#define BTN_DOWN 73 // J3
#define BTN_LEFT 72 // J2
#define BTN_RIGHT 14 // J1
#define BTN_CENTER 15 // J0
#define BTN_ENC BTN_CENTER
#define BTN_UP 75 // J4
#define BTN_DOWN 73 // J3
#define BTN_LEFT 72 // J2
#define BTN_RIGHT 14 // J1
#define BTN_CENTER 15 // J0
#define BTN_ENC BTN_CENTER
#define BEEPER_PIN 4 // G5
#define BEEPER_PIN 4 // G5
#define STAT_LED_RED_PIN 32 // C5
#define STAT_LED_BLUE_PIN 31 // C6 (Actually green)
@@ -259,8 +260,8 @@
//
// SD Card
//
#define SDSS 53 // B0
#define SD_DETECT_PIN 9 // H6
#define SDSS 53 // B0
#define SD_DETECT_PIN 9 // H6
#define MAX_PIN THERMO_SCK_PIN
@@ -272,8 +273,6 @@
#define SPINDLE_DIR_PIN 67 // K5
// Check if all pins are defined in mega/pins_arduino.h
#include <Arduino.h>
static_assert(NUM_DIGITAL_PINS > MAX_PIN, "add missing pins to [arduino dir]/hardware/arduino/avr/variants/mega/pins_arduino.h based on fastio.h"
+3 -1
View File
@@ -106,7 +106,9 @@
#endif
#define HEATER_BED_PIN 4
#define FAN_PIN 8
#ifndef FAN_PIN
#define FAN_PIN 8
#endif
#define FAN1_PIN 6
//
+12 -10
View File
@@ -57,13 +57,13 @@
#define X_DIR_PIN 47
#define X_ENABLE_PIN 49
#define Y_STEP_PIN 39 // A6
#define Y_DIR_PIN 40 // A0
#define Y_STEP_PIN 39 // A6
#define Y_DIR_PIN 40 // A0
#define Y_ENABLE_PIN 38
#define Z_STEP_PIN 42 // A2
#define Z_DIR_PIN 43 // A6
#define Z_ENABLE_PIN 41 // A1
#define Z_STEP_PIN 42 // A2
#define Z_DIR_PIN 43 // A6
#define Z_ENABLE_PIN 41 // A1
#define E0_STEP_PIN 45
#define E0_DIR_PIN 44
@@ -83,11 +83,13 @@
//
// Heaters / Fans
//
#define HEATER_0_PIN 7 // EXTRUDER 1
#define HEATER_1_PIN 8 // EXTRUDER 2
#define HEATER_BED_PIN 3 // BED
#define HEATER_0_PIN 7 // EXTRUDER 1
#define HEATER_1_PIN 8 // EXTRUDER 2
#define HEATER_BED_PIN 3 // BED
#define FAN_PIN 9
#ifndef FAN_PIN
#define FAN_PIN 9
#endif
//
// Misc. Functions
@@ -122,7 +124,7 @@
#define BTN_EN2 -1
#define BTN_ENC -1
#define SD_DETECT_PIN -1 // Minitronics doesn't use this
#define SD_DETECT_PIN -1 // Minitronics doesn't use this
#endif
//
+1 -1
View File
@@ -33,7 +33,7 @@
#error "MKS GEN 1.3/1.4 supports up to 2 hotends / E-steppers. Comment out this line to continue."
#endif
#define BOARD_NAME "MKS GEN > v1.3"
#define BOARD_NAME "MKS GEN >= v1.3"
//
// Heaters / Fans
+13
View File
@@ -36,4 +36,17 @@
// Power outputs EFBF or EFBE
#define MOSFET_D_PIN 7
//
// CS Pins wired to avoid conflict with the LCD
// See https://www.thingiverse.com/asset:66604
//
#ifndef X_CS_PIN
#define X_CS_PIN 59
#endif
#ifndef Y_CS_PIN
#define Y_CS_PIN 63
#endif
#include "pins_RAMPS.h"
+11 -9
View File
@@ -108,13 +108,13 @@
#define E0_DIR_PIN 21
#define E0_ENABLE_PIN 10
#define E1_STEP_PIN -1 // 21
#define E1_DIR_PIN -1 // 20
#define E1_ENABLE_PIN -1 // 19
#define E1_STEP_PIN -1 // 21
#define E1_DIR_PIN -1 // 20
#define E1_ENABLE_PIN -1 // 19
#define E2_STEP_PIN -1 // 21
#define E2_DIR_PIN -1 // 20
#define E2_ENABLE_PIN -1 // 18
#define E2_STEP_PIN -1 // 21
#define E2_DIR_PIN -1 // 20
#define E2_ENABLE_PIN -1 // 18
//
// Temperature Sensors
@@ -126,10 +126,12 @@
//
// Heaters / Fans
//
#define HEATER_0_PIN 3 // DONE PWM on RIGHT connector
#define HEATER_0_PIN 3 // DONE PWM on RIGHT connector
#define HEATER_BED_PIN 4
#define FAN_PIN 14 // PWM on MIDDLE connector
#ifndef FAN_PIN
#define FAN_PIN 14 // PWM on MIDDLE connector
#endif
//
// Misc. Functions
@@ -145,4 +147,4 @@
#define __GS 18
#define __GD 13
#define UNUSED_PWM 14 // PWM on LEFT connector
#define UNUSED_PWM 14 // PWM on LEFT connector
+7 -5
View File
@@ -107,12 +107,12 @@
#define E0_DIR_PIN 27
#define E0_ENABLE_PIN 24
#define E1_STEP_PIN -1 // 19
#define E1_DIR_PIN -1 // 18
#define E1_STEP_PIN -1 // 19
#define E1_DIR_PIN -1 // 18
#define E1_ENABLE_PIN 24
#define E2_STEP_PIN -1 // 17
#define E2_DIR_PIN -1 // 16
#define E2_STEP_PIN -1 // 17
#define E2_DIR_PIN -1 // 16
#define E2_ENABLE_PIN 24
//
@@ -125,7 +125,9 @@
//
#define HEATER_0_PIN 4
#define FAN_PIN 3
#ifndef FAN_PIN
#define FAN_PIN 3
#endif
//
// Misc. Functions
+3 -2
View File
@@ -110,8 +110,9 @@
#define HEATER_2_PIN 45 // F7
#define HEATER_BED_PIN 14 // C4 PWM3C
#define FAN_PIN 16 // C6 PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A
#endif
//
// Misc. Functions
+3 -1
View File
@@ -190,7 +190,9 @@
#endif
#endif
#define FAN_PIN 16 // C6 PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A
#endif
//
// LCD / Controller
+3 -1
View File
@@ -127,7 +127,9 @@
#define HEATER_2_PIN 6
#define HEATER_BED_PIN 3
#define FAN_PIN 8
#ifndef FAN_PIN
#define FAN_PIN 8
#endif
#define FAN1_PIN 6
#define FAN2_PIN 2
+6 -2
View File
@@ -88,11 +88,15 @@
#if ENABLED(RAMPS_V_1_0)
#define HEATER_0_PIN 12
#define HEATER_BED_PIN -1
#define FAN_PIN 11
#ifndef FAN_PIN
#define FAN_PIN 11
#endif
#else // RAMPS_V_1_1 or RAMPS_V_1_2
#define HEATER_0_PIN 10
#define HEATER_BED_PIN 8
#define FAN_PIN 9
#ifndef FAN_PIN
#define FAN_PIN 9
#endif
#endif
//
+7 -6
View File
@@ -36,8 +36,8 @@
//
// MOSFET changes
//
#define RAMPS_D10_PIN 9 // EXTRUDER 1
#define MOSFET_D_PIN 12 // EXTRUDER 2 or FAN
#define RAMPS_D10_PIN 9 // EXTRUDER 1
#define MOSFET_D_PIN 12 // EXTRUDER 2 or FAN
#include "pins_RAMPS.h"
@@ -74,9 +74,9 @@
// SPI for Max6675 or Max31855 Thermocouple
#undef MAX6675_SS
#if DISABLED(SDSUPPORT)
#define MAX6675_SS 53 // Don't use pin 53 if there is even the remote possibility of using Display/SD card
#define MAX6675_SS 53 // Don't use pin 53 if there is even the remote possibility of using Display/SD card
#else
#define MAX6675_SS 49 // Don't use pin 49 as this is tied to the switch inside the SD card socket to detect if there is an SD card present
#define MAX6675_SS 49 // Don't use pin 49 as this is tied to the switch inside the SD card socket to detect if there is an SD card present
#endif
//
@@ -85,8 +85,9 @@
#undef HEATER_BED_PIN
#define HEATER_BED_PIN 10
#undef FAN_PIN
#define FAN_PIN 8 // Same as RAMPS_13_EEF
#ifndef FAN_PIN
#define FAN_PIN 8 // Same as RAMPS_13_EEF
#endif
//
// Misc. Functions
+5 -5
View File
@@ -39,12 +39,12 @@
// Channels available for DAC, For Rigidboard there are 4
#define DAC_STEPPER_ORDER { 0, 1, 2, 3 }
#define DAC_STEPPER_SENSE 0.05 // sense resistors on rigidboard stepper chips are .05 value
#define DAC_STEPPER_SENSE 0.05 // sense resistors on rigidboard stepper chips are .05 value
#define DAC_STEPPER_ADDRESS 0
#define DAC_STEPPER_MAX 4096 // was 5000 but max allowable value is actually 4096
#define DAC_STEPPER_VREF 1 // internal Vref, gain 2x = 4.096V
#define DAC_STEPPER_GAIN 1 // value of 1 here sets gain of 2
#define DAC_DISABLE_PIN 42 // set low to enable DAC
#define DAC_STEPPER_MAX 4096 // was 5000 but max allowable value is actually 4096
#define DAC_STEPPER_VREF 1 // internal Vref, gain 2x = 4.096V
#define DAC_STEPPER_GAIN 1 // value of 1 here sets gain of 2
#define DAC_DISABLE_PIN 42 // set low to enable DAC
#define DAC_OR_ADDRESS 0x01
#ifndef DAC_MOTOR_CURRENT_DEFAULT
+2 -2
View File
@@ -100,7 +100,7 @@
#define Z_ENABLE_PIN 26
#define E0_ENABLE_PIN 14
#if ENABLED(LCD_I2C_PANELOLU2)
#if !defined(FAN_PIN) && ENABLED(LCD_I2C_PANELOLU2)
#define FAN_PIN 4 // Uses Transistor1 (PWM) on Panelolu2's Sanguino Adapter Board to drive the fan
#endif
@@ -114,7 +114,7 @@
#endif
#if MB(AZTEEG_X1) || MB(STB_11) || ENABLED(IS_MELZI)
#if !defined(FAN_PIN) && (MB(AZTEEG_X1) || MB(STB_11) || ENABLED(IS_MELZI))
#define FAN_PIN 4 // Works for Panelolu2 too
#endif
+3 -1
View File
@@ -114,7 +114,9 @@
#define HEATER_0_PIN 15 // C5 PWM3B - Extruder
#define HEATER_BED_PIN 14 // C4 PWM3C - Bed
#define FAN_PIN 16 // C6 PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A
#endif
//
// Misc. Functions
+4 -2
View File
@@ -91,7 +91,7 @@
#define E1_MS2_PIN 64
#define DIGIPOTSS_PIN 38
#define DIGIPOT_CHANNELS {4,5,3,0,1} // X Y Z E0 E1 digipot channels to stepper driver mapping
#define DIGIPOT_CHANNELS {4,5,3,0,1} // X Y Z E0 E1 digipot channels to stepper driver mapping
//
// Temperature Sensors
@@ -106,7 +106,9 @@
#define HEATER_1_PIN 7
#define HEATER_BED_PIN 3
#define FAN_PIN 8
#ifndef FAN_PIN
#define FAN_PIN 8
#endif
#define FAN1_PIN 6
#define FAN2_PIN 2
+7 -6
View File
@@ -98,12 +98,13 @@
#define HEATER_0_PIN 4
#define HEATER_BED_PIN 3
#if GEN7_VERSION >= 13
// Gen7 v1.3 removed the fan pin
#define FAN_PIN -1
#else
#define FAN_PIN 31
#ifndef FAN_PIN
#if GEN7_VERSION >= 13
// Gen7 v1.3 removed the fan pin
#define FAN_PIN -1
#else
#define FAN_PIN 31
#endif
#endif
//
+3 -1
View File
@@ -56,7 +56,9 @@
#define FIL_RUNOUT_PIN 34 // X_MAX unless overridden
#endif
#define FAN_PIN 5
#ifndef FAN_PIN
#define FAN_PIN 5
#endif
#define HEATER_0_PIN 7
+3 -1
View File
@@ -149,7 +149,9 @@
//
#define HEATER_0_PIN 15 // C5 PWM3B Extruder
#define HEATER_BED_PIN 14 // C4 PWM3C
#define FAN_PIN 16 // C6 PWM3A Fan
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A Fan
#endif
//
// Misc. Functions
+3 -1
View File
@@ -127,7 +127,9 @@
#define HEATER_0_PIN 15 // C5 PWM3B - Extruder
#define HEATER_BED_PIN 14 // C4 PWM3C
#define FAN_PIN 16 // C6 PWM3A
#ifndef FAN_PIN
#define FAN_PIN 16 // C6 PWM3A
#endif
//
// Misc. Functions
+3 -2
View File
@@ -29,8 +29,9 @@
#endif
#define IS_RAMPS_EFB
#define RAMPS_D9_PIN 44
#define ORIG_E0_AUTO_FAN_PIN RAMPS_D9_PIN
#define RAMPS_D9_PIN 44
#define FAN2_PIN 9
#define ORIG_E0_AUTO_FAN_PIN 9
#include "pins_RAMPS_13.h"
+3 -7
View File
@@ -30,11 +30,7 @@
#define IS_RAMPS_EFB
#include "pins_RAMPS_13.h"
#define FAN2_PIN 44
#define ORIG_E0_AUTO_FAN_PIN 44
#define FAN2_PIN 44
#undef E1_STEP_PIN
#undef E1_DIR_PIN
#undef E1_ENABLE_PIN
#undef E1_CS_PIN
#include "pins_RAMPS.h"
+3 -1
View File
@@ -93,7 +93,9 @@
#define HEATER_1_PIN 3
#define HEATER_BED_PIN 4
#define FAN_PIN 7
#ifndef FAN_PIN
#define FAN_PIN 7
#endif
//
// Misc. Functions
+3 -1
View File
@@ -99,7 +99,9 @@
#define HEATER_1_PIN 3
#define HEATER_BED_PIN 4
#define FAN_PIN 7
#ifndef FAN_PIN
#define FAN_PIN 7
#endif
//
// Misc. Functions
+357 -309
View File
File diff suppressed because it is too large Load Diff
+91 -55
View File
@@ -49,9 +49,6 @@ enum BlockFlagBit : char {
// from a safe speed (in consideration of jerking from zero speed).
BLOCK_BIT_NOMINAL_LENGTH,
// The block is busy, being interpreted by the stepper ISR
BLOCK_BIT_BUSY,
// The block is segment 2+ of a longer move
BLOCK_BIT_CONTINUED,
@@ -62,7 +59,6 @@ enum BlockFlagBit : char {
enum BlockFlag : char {
BLOCK_FLAG_RECALCULATE = _BV(BLOCK_BIT_RECALCULATE),
BLOCK_FLAG_NOMINAL_LENGTH = _BV(BLOCK_BIT_NOMINAL_LENGTH),
BLOCK_FLAG_BUSY = _BV(BLOCK_BIT_BUSY),
BLOCK_FLAG_CONTINUED = _BV(BLOCK_BIT_CONTINUED),
BLOCK_FLAG_SYNC_POSITION = _BV(BLOCK_BIT_SYNC_POSITION)
};
@@ -78,7 +74,7 @@ enum BlockFlag : char {
*/
typedef struct {
uint8_t flag; // Block flags (See BlockFlag enum above)
volatile uint8_t flag; // Block flags (See BlockFlag enum above) - Modified by ISR and main thread!
// Fields used by the motion planner to manage acceleration
float nominal_speed_sqr, // The nominal speed for this block in (mm/sec)^2
@@ -103,18 +99,18 @@ typedef struct {
uint8_t active_extruder; // The extruder to move (if E move)
#if ENABLED(MIXING_EXTRUDER)
uint32_t mix_event_count[MIXING_STEPPERS]; // Scaled step_event_count for the mixing steppers
uint32_t mix_steps[MIXING_STEPPERS]; // Scaled steps[E_AXIS] for the mixing steppers
#endif
// Settings for the trapezoid generator
uint32_t accelerate_until, // The index of the step event on which to stop acceleration
decelerate_after; // The index of the step event on which to start decelerating
#if ENABLED(BEZIER_JERK_CONTROL)
uint32_t cruise_rate; // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
uint32_t acceleration_time, // Acceleration time and deceleration time in STEP timer counts
deceleration_time;
uint32_t acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
#if ENABLED(S_CURVE_ACCELERATION)
uint32_t cruise_rate, // The actual cruise rate to use, between end of the acceleration phase and start of deceleration phase
acceleration_time, // Acceleration time and deceleration time in STEP timer counts
deceleration_time,
acceleration_time_inverse, // Inverse of acceleration and deceleration periods, expressed as integer. Scale depends on CPU being used
deceleration_time_inverse;
#else
uint32_t acceleration_rate; // The acceleration rate used for acceleration calculation
@@ -125,7 +121,7 @@ typedef struct {
// Advance extrusion
#if ENABLED(LIN_ADVANCE)
bool use_advance_lead;
uint16_t advance_speed, // Timer value for extruder speed offset
uint16_t advance_speed, // STEP timer value for extruder speed offset ISR
max_adv_steps, // max. advance steps to get cruising speed pressure (not always nominal_speed!)
final_adv_steps; // advance steps due to exit speed
float e_D_ratio;
@@ -148,7 +144,7 @@ typedef struct {
} block_t;
#define HAS_POSITION_FLOAT (ENABLED(LIN_ADVANCE) || ENABLED(SCARA_FEEDRATE_SCALING))
#define HAS_POSITION_FLOAT (ENABLED(LIN_ADVANCE) || HAS_FEEDRATE_SCALING)
#define BLOCK_MOD(n) ((n)&(BLOCK_BUFFER_SIZE-1))
@@ -170,11 +166,12 @@ class Planner {
*/
static block_t block_buffer[BLOCK_BUFFER_SIZE];
static volatile uint8_t block_buffer_head, // Index of the next block to be pushed
block_buffer_nonbusy, // Index of the first non busy block
block_buffer_planned, // Index of the optimally planned block
block_buffer_tail; // Index of the busy block, if any
static uint16_t cleaning_buffer_counter; // A counter to disable queuing of blocks
static uint8_t delay_before_delivering, // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
block_buffer_planned; // Index of the optimally planned block
static uint8_t delay_before_delivering; // This counter delays delivery of blocks when queue becomes empty to allow the opportunity of merging blocks
#if ENABLED(DISTINCT_E_FACTORS)
static uint8_t last_extruder; // Respond to extruder change
@@ -191,19 +188,30 @@ class Planner {
// May be auto-adjusted by a filament width sensor
#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
static uint32_t max_acceleration_mm_per_s2[XYZE_N], // (mm/s^2) M201 XYZE
max_acceleration_steps_per_s2[XYZE_N], // (steps/s^2) Derived from mm_per_s2
min_segment_time_us; // (µs) M205 B
static float max_feedrate_mm_s[XYZE_N], // (mm/s) M203 XYZE - Max speeds
axis_steps_per_mm[XYZE_N], // (steps) M92 XYZE - Steps per millimeter
steps_to_mm[XYZE_N], // (mm) Millimeters per step
min_feedrate_mm_s, // (mm/s) M205 S - Minimum linear feedrate
acceleration, // (mm/s^2) M204 S - Normal acceleration. DEFAULT ACCELERATION for all printing moves.
retract_acceleration, // (mm/s^2) M204 R - Retract acceleration. Filament pull-back and push-forward while standing still in the other axes
travel_acceleration, // (mm/s^2) M204 T - Travel acceleration. DEFAULT ACCELERATION for all NON printing moves.
min_travel_feedrate_mm_s; // (mm/s) M205 T - Minimum travel feedrate
static uint32_t min_segment_time_us; // Use 'M205 B<µs>' to override
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 ENABLED(JUNCTION_DEVIATION)
static float junction_deviation_mm; // (mm) M205 J
#if ENABLED(LIN_ADVANCE)
#if ENABLED(DISTINCT_E_FACTORS)
static float max_e_jerk[EXTRUDERS]; // Calculated from junction_deviation_mm
#else
static float max_e_jerk;
#endif
#endif
#else
static float max_jerk[XYZE]; // (mm/s^2) M205 XYZE - The largest speed change requiring no acceleration.
#endif
#if HAS_LEVELING
static bool leveling_active; // Flag that bed leveling is enabled
@@ -311,7 +319,7 @@ class Planner {
static void refresh_positioning();
FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
e_factor[e] = (flow_percentage[e] * 0.01
e_factor[e] = (flow_percentage[e] * 0.01f
#if DISABLED(NO_VOLUMETRICS)
* volumetric_multiplier[e]
#endif
@@ -349,19 +357,19 @@ class Planner {
* Returns 0.0 if Z is past the specified 'Fade Height'.
*/
inline static float fade_scaling_factor_for_z(const float &rz) {
static float z_fade_factor = 1.0;
static float z_fade_factor = 1;
if (z_fade_height) {
if (rz >= z_fade_height) return 0.0;
if (rz >= z_fade_height) return 0;
if (last_fade_z != rz) {
last_fade_z = rz;
z_fade_factor = 1.0 - rz * inverse_z_fade_height;
z_fade_factor = 1 - rz * inverse_z_fade_height;
}
return z_fade_factor;
}
return 1.0;
return 1;
}
FORCE_INLINE static void force_fade_recalc() { last_fade_z = -999.999; }
FORCE_INLINE static void force_fade_recalc() { last_fade_z = -999.999f; }
FORCE_INLINE static void set_z_fade_height(const float &zfh) {
z_fade_height = zfh > 0 ? zfh : 0;
@@ -377,7 +385,7 @@ class Planner {
FORCE_INLINE static float fade_scaling_factor_for_z(const float &rz) {
UNUSED(rz);
return 1.0;
return 1;
}
FORCE_INLINE static bool leveling_active_at_z(const float &rz) { UNUSED(rz); return true; }
@@ -428,11 +436,14 @@ class Planner {
#define ARG_Z const float &rz
#endif
// Number of moves currently in the planner
// Number of moves currently in the planner including the busy block, if any
FORCE_INLINE static uint8_t movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_tail); }
// Number of nonbusy moves currently in the planner
FORCE_INLINE static uint8_t nonbusy_movesplanned() { return BLOCK_MOD(block_buffer_head - block_buffer_nonbusy); }
// Remove all blocks from the buffer
FORCE_INLINE static void clear_block_buffer() { block_buffer_head = block_buffer_tail = 0; }
FORCE_INLINE static void clear_block_buffer() { block_buffer_nonbusy = block_buffer_planned = block_buffer_head = block_buffer_tail = 0; }
// Check if movement queue is full
FORCE_INLINE static bool is_full() { return block_buffer_tail == next_block_index(block_buffer_head); }
@@ -634,7 +645,7 @@ class Planner {
static block_t* get_current_block() {
// Get the number of moves in the planner queue so far
uint8_t nr_moves = movesplanned();
const uint8_t nr_moves = movesplanned();
// If there are any moves queued ...
if (nr_moves) {
@@ -658,8 +669,14 @@ class Planner {
block_buffer_runtime_us -= block->segment_time_us; // We can't be sure how long an active block will take, so don't count it.
#endif
// Mark the block as busy, so the planner does not attempt to replan it
SBI(block->flag, BLOCK_BIT_BUSY);
// As this block is busy, advance the nonbusy block pointer
block_buffer_nonbusy = next_block_index(block_buffer_tail);
// Push block_buffer_planned pointer, if encountered.
if (block_buffer_tail == block_buffer_planned)
block_buffer_planned = block_buffer_nonbusy;
// Return the block
return block;
}
@@ -677,27 +694,18 @@ class Planner {
* NB: There MUST be a current block to call this function!!
*/
FORCE_INLINE static void discard_current_block() {
if (has_blocks_queued()) { // Discard non-empty buffer.
uint8_t block_index = next_block_index( block_buffer_tail );
// Push block_buffer_planned pointer, if encountered.
if (!has_blocks_queued()) block_buffer_planned = block_index;
block_buffer_tail = block_index;
}
if (has_blocks_queued())
block_buffer_tail = next_block_index(block_buffer_tail);
}
#if ENABLED(ULTRA_LCD)
static uint16_t block_buffer_runtime() {
// Protect the access to the variable. Only required for AVR, as
// any 32bit CPU offers atomic access to 32bit variables
bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
millis_t bbru = block_buffer_runtime_us;
// Reenable Stepper ISR
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
// To translate µs to ms a division by 1000 would be required.
@@ -710,14 +718,11 @@ class Planner {
}
static void clear_block_buffer_runtime() {
// Protect the access to the variable. Only required for AVR, as
// any 32bit CPU offers atomic access to 32bit variables
bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
block_buffer_runtime_us = 0;
// Reenable Stepper ISR
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
}
@@ -730,6 +735,20 @@ class Planner {
static void autotemp_M104_M109();
#endif
#if ENABLED(JUNCTION_DEVIATION)
FORCE_INLINE static void recalculate_max_e_jerk() {
#define GET_MAX_E_JERK(N) SQRT(SQRT(0.5) * junction_deviation_mm * (N) * RECIPROCAL(1.0 - SQRT(0.5)))
#if ENABLED(LIN_ADVANCE)
#if ENABLED(DISTINCT_E_FACTORS)
for (uint8_t i = 0; i < EXTRUDERS; i++)
max_e_jerk[i] = GET_MAX_E_JERK(max_acceleration_mm_per_s2[E_AXIS + i]);
#else
max_e_jerk = GET_MAX_E_JERK(max_acceleration_mm_per_s2[E_AXIS]);
#endif
#endif
}
#endif
private:
/**
@@ -769,7 +788,7 @@ class Planner {
return target_velocity_sqr - 2 * accel * distance;
}
#if ENABLED(BEZIER_JERK_CONTROL)
#if ENABLED(S_CURVE_ACCELERATION)
/**
* Calculate the speed reached given initial speed, acceleration and distance
*/
@@ -790,6 +809,23 @@ class Planner {
static void recalculate();
#if ENABLED(JUNCTION_DEVIATION)
FORCE_INLINE static void normalize_junction_vector(float (&vector)[XYZE]) {
float magnitude_sq = 0;
LOOP_XYZE(idx) if (vector[idx]) magnitude_sq += sq(vector[idx]);
const float inv_magnitude = RSQRT(magnitude_sq);
LOOP_XYZE(idx) vector[idx] *= inv_magnitude;
}
FORCE_INLINE static float limit_value_by_axis_maximum(const float &max_value, float (&unit_vec)[XYZE]) {
float limit_value = max_value;
LOOP_XYZE(idx) if (unit_vec[idx]) // Avoid divide by zero
NOMORE(limit_value, ABS(max_acceleration_mm_per_s2[idx] / unit_vec[idx]));
return limit_value;
}
#endif // JUNCTION_DEVIATION
};
#define PLANNER_XY_FEEDRATE() (MIN(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]))
+14 -14
View File
@@ -37,12 +37,12 @@
#include "Marlin.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
#define MIN_STEP 0.002f
#define MAX_STEP 0.1f
#define SIGMA 0.1f
// Compute the linear interpolation between two real numbers.
inline static float interp(float a, float b, float t) { return (1.0 - t) * a + t * b; }
inline static float interp(float a, float b, float t) { return (1.0f - t) * a + t * b; }
/**
* Compute a Bézier curve using the De Casteljau's algorithm (see
@@ -111,7 +111,7 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
first1 = position[Y_AXIS] + offset[1],
second0 = target[X_AXIS] + offset[2],
second1 = target[Y_AXIS] + offset[3];
float t = 0.0;
float t = 0;
float bez_target[4];
bez_target[X_AXIS] = position[X_AXIS];
@@ -120,7 +120,7 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
millis_t next_idle_ms = millis() + 200UL;
while (t < 1.0) {
while (t < 1) {
thermalManager.manage_heater();
millis_t now = millis();
@@ -133,16 +133,16 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
// close to a linear interpolation.
bool did_reduce = false;
float new_t = t + step;
NOMORE(new_t, 1.0);
NOMORE(new_t, 1);
float new_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], new_t),
new_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], new_t);
for (;;) {
if (new_t - t < (MIN_STEP)) break;
const float candidate_t = 0.5 * (t + new_t),
const float candidate_t = 0.5f * (t + new_t),
candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t),
candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t),
interp_pos0 = 0.5 * (bez_target[X_AXIS] + new_pos0),
interp_pos1 = 0.5 * (bez_target[Y_AXIS] + new_pos1);
interp_pos0 = 0.5f * (bez_target[X_AXIS] + new_pos0),
interp_pos1 = 0.5f * (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;
@@ -153,12 +153,12 @@ void cubic_b_spline(const float position[NUM_AXIS], const float target[NUM_AXIS]
// If we did not reduce the step, maybe we should enlarge it.
if (!did_reduce) for (;;) {
if (new_t - t > MAX_STEP) break;
const float candidate_t = t + 2.0 * (new_t - t);
if (candidate_t >= 1.0) break;
const float candidate_t = t + 2 * (new_t - t);
if (candidate_t >= 1) break;
const float candidate_pos0 = eval_bezier(position[X_AXIS], first0, second0, target[X_AXIS], candidate_t),
candidate_pos1 = eval_bezier(position[Y_AXIS], first1, second1, target[Y_AXIS], candidate_t),
interp_pos0 = 0.5 * (bez_target[X_AXIS] + candidate_pos0),
interp_pos1 = 0.5 * (bez_target[Y_AXIS] + candidate_pos1);
interp_pos0 = 0.5f * (bez_target[X_AXIS] + candidate_pos0),
interp_pos1 = 0.5f * (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;
+72 -43
View File
@@ -42,58 +42,76 @@ job_recovery_info_t job_recovery_info;
JobRecoveryPhase job_recovery_phase = JOB_RECOVERY_IDLE;
uint8_t job_recovery_commands_count; //=0
char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
// Extern
extern uint8_t commands_in_queue, cmd_queue_index_r;
// Private
static char sd_filename[MAXPATHNAMELENGTH];
extern uint8_t active_extruder, commands_in_queue, cmd_queue_index_r;
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
void debug_print_job_recovery(const bool recovery) {
SERIAL_PROTOCOLPAIR("valid_head:", (int)job_recovery_info.valid_head);
SERIAL_PROTOCOLLNPAIR(" valid_foot:", (int)job_recovery_info.valid_foot);
SERIAL_PROTOCOLLNPGM("---- Job Recovery Info ----");
SERIAL_PROTOCOLPAIR("valid_head:", int(job_recovery_info.valid_head));
SERIAL_PROTOCOLLNPAIR(" valid_foot:", int(job_recovery_info.valid_foot));
if (job_recovery_info.valid_head) {
if (job_recovery_info.valid_head == job_recovery_info.valid_foot) {
SERIAL_PROTOCOLPGM("current_position");
LOOP_XYZE(i) SERIAL_PROTOCOLPAIR(": ", job_recovery_info.current_position[i]);
SERIAL_PROTOCOLPGM("current_position: ");
LOOP_XYZE(i) {
SERIAL_PROTOCOL(job_recovery_info.current_position[i]);
if (i < E_AXIS) SERIAL_CHAR(',');
}
SERIAL_EOL();
SERIAL_PROTOCOLLNPAIR("feedrate: ", job_recovery_info.feedrate);
SERIAL_PROTOCOLPGM("target_temperature");
HOTEND_LOOP() SERIAL_PROTOCOLPAIR(": ", job_recovery_info.target_temperature[e]);
SERIAL_EOL();
SERIAL_PROTOCOLPGM("fanSpeeds");
for(uint8_t i = 0; i < FAN_COUNT; i++) SERIAL_PROTOCOLPAIR(": ", job_recovery_info.fanSpeeds[i]);
#if HOTENDS > 1
SERIAL_PROTOCOLLNPAIR("active_hotend: ", int(job_recovery_info.active_hotend));
#endif
SERIAL_PROTOCOLPGM("target_temperature: ");
HOTEND_LOOP() {
SERIAL_PROTOCOL(job_recovery_info.target_temperature[e]);
if (e < HOTENDS - 1) SERIAL_CHAR(',');
}
SERIAL_EOL();
#if HAS_HEATED_BED
SERIAL_PROTOCOLLNPAIR("target_temperature_bed: ", job_recovery_info.target_temperature_bed);
#endif
#if FAN_COUNT
SERIAL_PROTOCOLPGM("fanSpeeds: ");
for (int8_t i = 0; i < FAN_COUNT; i++) {
SERIAL_PROTOCOL(job_recovery_info.fanSpeeds[i]);
if (i < FAN_COUNT - 1) SERIAL_CHAR(',');
}
SERIAL_EOL();
#endif
#if HAS_LEVELING
SERIAL_PROTOCOLPAIR("leveling: ", int(job_recovery_info.leveling));
SERIAL_PROTOCOLLNPAIR(" fade: ", int(job_recovery_info.fade));
#endif
#if HAS_HEATED_BED
SERIAL_PROTOCOLLNPAIR("target_temperature_bed: ", job_recovery_info.target_temperature_bed);
#endif
SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", job_recovery_info.cmd_queue_index_r);
SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", job_recovery_info.commands_in_queue);
SERIAL_PROTOCOLLNPAIR("cmd_queue_index_r: ", int(job_recovery_info.cmd_queue_index_r));
SERIAL_PROTOCOLLNPAIR("commands_in_queue: ", int(job_recovery_info.commands_in_queue));
if (recovery)
for (uint8_t i = 0; i < job_recovery_commands_count; i++) SERIAL_PROTOCOLLNPAIR("> ", job_recovery_commands[i]);
else
for (uint8_t i = 0; i < job_recovery_info.commands_in_queue; i++) SERIAL_PROTOCOLLNPAIR("> ", job_recovery_info.command_queue[i]);
SERIAL_PROTOCOLLNPAIR("sd_filename: ", sd_filename);
SERIAL_PROTOCOLLNPAIR("sd_filename: ", job_recovery_info.sd_filename);
SERIAL_PROTOCOLLNPAIR("sdpos: ", job_recovery_info.sdpos);
SERIAL_PROTOCOLLNPAIR("print_job_elapsed: ", job_recovery_info.print_job_elapsed);
}
else
SERIAL_PROTOCOLLNPGM("INVALID DATA");
}
SERIAL_PROTOCOLLNPGM("---------------------------");
}
#endif // DEBUG_POWER_LOSS_RECOVERY
/**
* Check for Print Job Recovery
* If the file has a saved state, populate the job_recovery_commands queue
* Check for Print Job Recovery during setup()
*
* If a saved state exists, populate job_recovery_commands with
* commands to restore the machine state and continue the file.
*/
void do_print_job_recovery() {
//if (job_recovery_commands_count > 0) return;
void check_print_job_recovery() {
memset(&job_recovery_info, 0, sizeof(job_recovery_info));
ZERO(job_recovery_commands);
@@ -102,7 +120,7 @@ void do_print_job_recovery() {
if (card.cardOK) {
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
SERIAL_PROTOCOLLNPAIR("Init job recovery info. Size: ", (int)sizeof(job_recovery_info));
SERIAL_PROTOCOLLNPAIR("Init job recovery info. Size: ", int(sizeof(job_recovery_info)));
#endif
if (card.jobRecoverFileExists()) {
@@ -122,7 +140,9 @@ void do_print_job_recovery() {
strcpy_P(job_recovery_commands[ind++], PSTR("G92.0 Z0")); // Ensure Z is equal to 0
strcpy_P(job_recovery_commands[ind++], PSTR("G1 Z2")); // Raise Z by 2mm (we hope!)
strcpy_P(job_recovery_commands[ind++], PSTR("G28 R0"
#if !IS_KINEMATIC
#if ENABLED(MARLIN_DEV_MODE)
" S"
#elif !IS_KINEMATIC
" X Y" // Home X and Y for Cartesian
#endif
));
@@ -130,10 +150,12 @@ void do_print_job_recovery() {
char str_1[16], str_2[16];
#if HAS_LEVELING
// Restore leveling state before G92 sets Z
// This ensures the steppers correspond to the native Z
dtostrf(job_recovery_info.fade, 1, 1, str_1);
sprintf_P(job_recovery_commands[ind++], PSTR("M420 S%i Z%s"), int(job_recovery_info.leveling), str_1);
if (job_recovery_info.fade || job_recovery_info.leveling) {
// Restore leveling state before G92 sets Z
// This ensures the steppers correspond to the native Z
dtostrf(job_recovery_info.fade, 1, 1, str_1);
sprintf_P(job_recovery_commands[ind++], PSTR("M420 S%i Z%s"), int(job_recovery_info.leveling), str_1);
}
#endif
dtostrf(job_recovery_info.current_position[Z_AXIS] + 2, 1, 3, str_1);
@@ -145,23 +167,21 @@ void do_print_job_recovery() {
);
sprintf_P(job_recovery_commands[ind++], PSTR("G92.0 Z%s E%s"), str_1, str_2); // Current Z + 2 and E
strcpy_P(job_recovery_commands[ind++], PSTR("M117 Continuing..."));
uint8_t r = job_recovery_info.cmd_queue_index_r;
while (job_recovery_info.commands_in_queue) {
uint8_t r = job_recovery_info.cmd_queue_index_r, c = job_recovery_info.commands_in_queue;
while (c--) {
strcpy(job_recovery_commands[ind++], job_recovery_info.command_queue[r]);
job_recovery_info.commands_in_queue--;
r = (r + 1) % BUFSIZE;
}
if (job_recovery_info.sd_filename[0] == '/') job_recovery_info.sd_filename[0] = ' ';
sprintf_P(job_recovery_commands[ind++], PSTR("M23 %s"), job_recovery_info.sd_filename);
sprintf_P(job_recovery_commands[ind++], PSTR("M24 S%ld T%ld"), job_recovery_info.sdpos, job_recovery_info.print_job_elapsed);
job_recovery_commands_count = ind;
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
debug_print_job_recovery(true);
#endif
card.openFile(sd_filename, true);
card.setIndex(job_recovery_info.sdpos);
}
else {
if (job_recovery_info.valid_head != job_recovery_info.valid_foot)
@@ -173,7 +193,7 @@ void do_print_job_recovery() {
}
/**
* Save the current machine state to the "bin" file
* Save the current machine state to the power-loss recovery file
*/
void save_job_recovery_info() {
#if SAVE_INFO_INTERVAL_MS > 0
@@ -201,11 +221,20 @@ void save_job_recovery_info() {
// Machine state
COPY(job_recovery_info.current_position, current_position);
job_recovery_info.feedrate = feedrate_mm_s;
#if HOTENDS > 1
job_recovery_info.active_hotend = active_extruder;
#endif
COPY(job_recovery_info.target_temperature, thermalManager.target_temperature);
#if HAS_HEATED_BED
job_recovery_info.target_temperature_bed = thermalManager.target_temperature_bed;
#endif
COPY(job_recovery_info.fanSpeeds, fanSpeeds);
#if FAN_COUNT
COPY(job_recovery_info.fanSpeeds, fanSpeeds);
#endif
#if HAS_LEVELING
job_recovery_info.leveling = planner.leveling_active;
@@ -224,14 +253,14 @@ void save_job_recovery_info() {
COPY(job_recovery_info.command_queue, command_queue);
// Elapsed print job time
job_recovery_info.print_job_elapsed = print_job_timer.duration() * 1000UL;
job_recovery_info.print_job_elapsed = print_job_timer.duration();
// SD file position
card.getAbsFilename(sd_filename);
card.getAbsFilename(job_recovery_info.sd_filename);
job_recovery_info.sdpos = card.getIndex();
#if ENABLED(DEBUG_POWER_LOSS_RECOVERY)
SERIAL_PROTOCOLLNPGM("Saving job_recovery_info");
SERIAL_PROTOCOLLNPGM("Saving...");
debug_print_job_recovery(false);
#endif
+17 -7
View File
@@ -40,13 +40,21 @@ typedef struct {
// Machine state
float current_position[NUM_AXIS], feedrate;
int16_t target_temperature[HOTENDS],
fanSpeeds[FAN_COUNT];
#if HOTENDS > 1
uint8_t active_hotend;
#endif
int16_t target_temperature[HOTENDS];
#if HAS_HEATED_BED
int16_t target_temperature_bed;
#endif
#if FAN_COUNT
int16_t fanSpeeds[FAN_COUNT];
#endif
#if HAS_LEVELING
bool leveling;
float fade;
@@ -56,7 +64,8 @@ typedef struct {
uint8_t cmd_queue_index_r, commands_in_queue;
char command_queue[BUFSIZE][MAX_CMD_SIZE];
// SD File position
// SD Filename and position
char sd_filename[MAXPATHNAMELENGTH];
uint32_t sdpos;
// Job elapsed time
@@ -70,20 +79,21 @@ extern job_recovery_info_t job_recovery_info;
enum JobRecoveryPhase : unsigned char {
JOB_RECOVERY_IDLE,
JOB_RECOVERY_MAYBE,
JOB_RECOVERY_YES
JOB_RECOVERY_YES,
JOB_RECOVERY_DONE
};
extern JobRecoveryPhase job_recovery_phase;
#if HAS_LEVELING
#define APPEND_CMD_COUNT 7
#define APPEND_CMD_COUNT 9
#else
#define APPEND_CMD_COUNT 5
#define APPEND_CMD_COUNT 7
#endif
extern char job_recovery_commands[BUFSIZE + APPEND_CMD_COUNT][MAX_CMD_SIZE];
extern uint8_t job_recovery_commands_count;
void do_print_job_recovery();
void check_print_job_recovery();
void save_job_recovery_info();
#endif // _POWER_LOSS_RECOVERY_H_
+1 -1
View File
@@ -60,7 +60,7 @@ millis_t PrintCounter::deltaDuration() {
return lastDuration - tmp;
}
void PrintCounter::incFilamentUsed(double const &amount) {
void PrintCounter::incFilamentUsed(float const &amount) {
#if ENABLED(DEBUG_PRINTCOUNTER)
debug(PSTR("incFilamentUsed"));
#endif
+3 -3
View File
@@ -31,13 +31,13 @@
#include "stopwatch.h"
#include <avr/eeprom.h>
struct printStatistics { // 16 bytes (20 with real doubles)
struct printStatistics { // 16 bytes
//const uint8_t magic; // Magic header, it will always be 0x16
uint16_t totalPrints; // Number of prints
uint16_t finishedPrints; // Number of complete prints
uint32_t printTime; // Accumulated printing time
uint32_t longestPrint; // Longest successful print job
double filamentUsed; // Accumulated filament consumed in mm
float filamentUsed; // Accumulated filament consumed in mm
};
class PrintCounter: public Stopwatch {
@@ -122,7 +122,7 @@ class PrintCounter: public Stopwatch {
*
* @param amount The amount of filament used in mm
*/
static void incFilamentUsed(double const &amount);
static void incFilamentUsed(float const &amount);
/**
* @brief Reset the Print Statistics
+7 -9
View File
@@ -62,7 +62,7 @@ FORCE_INLINE void _draw_heater_status(const uint8_t x, const int8_t heater, cons
if (blink || !is_idle)
#endif
_draw_centered_temp(0.5 + (
_draw_centered_temp(0.5f + (
#if HAS_HEATED_BED
isBed ? thermalManager.degTargetBed() :
#endif
@@ -72,7 +72,7 @@ FORCE_INLINE void _draw_heater_status(const uint8_t x, const int8_t heater, cons
}
if (PAGE_CONTAINS(21, 28)) {
_draw_centered_temp(0.5 + (
_draw_centered_temp(0.5f + (
#if HAS_HEATED_BED
isBed ? thermalManager.degBed() :
#endif
@@ -108,11 +108,11 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
if (blink)
lcd_print(value);
else {
if (!axis_homed[axis])
if (!TEST(axis_homed, axis))
while (const char c = *value++) lcd_print(c <= '.' ? c : '?');
else {
#if DISABLED(HOME_AFTER_DEACTIVATE) && DISABLED(DISABLE_REDUCED_ACCURACY_WARNING)
if (!axis_known_position[axis])
if (!TEST(axis_known_position, axis))
lcd_printPGM(axis == Z_AXIS ? PSTR(" ") : PSTR(" "));
else
#endif
@@ -124,7 +124,7 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const
inline void lcd_implementation_status_message(const bool blink) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
// Get the UTF8 character count of the string
uint8_t slen = lcd_strlen(lcd_status_message);
@@ -162,10 +162,8 @@ inline void lcd_implementation_status_message(const bool blink) {
u8g.print('.'); // Always at 1+ spaces left, draw a dot
if (--chars) { // Draw a second dot if there's space
u8g.print('.');
if (--chars) {
// Print a second copy of the message
lcd_print_utf(lcd_status_message, LCD_WIDTH - (rlen+2));
}
if (--chars) // Print a second copy of the message
lcd_print_utf(lcd_status_message, LCD_WIDTH - (rlen + 2));
}
}
if (last_blink != blink) {
+2 -4
View File
@@ -617,7 +617,7 @@ void ST7920_Lite_Status_Screen::draw_status_message(const char *str) {
begin_data();
const uint8_t lcd_len = 16;
#if ENABLED(STATUS_MESSAGE_SCROLLING)
uint8_t slen = lcd_strlen(str);
// If the string fits into the LCD, just print it and do not scroll it
@@ -868,9 +868,7 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) {
#if ENABLED(DISABLE_REDUCED_ACCURACY_WARNING)
true
#else
axis_known_position[X_AXIS] &&
axis_known_position[Y_AXIS] &&
axis_known_position[Z_AXIS]
all_axes_known()
#endif
);
}
+1 -1
View File
@@ -18,7 +18,7 @@
#define STATUS_SCREEN_LITE_ST7920_CLASS_H
#include "macros.h"
#include "duration.h"
#include "duration_t.h"
typedef const __FlashStringHelper *progmem_str;
+541 -587
View File
File diff suppressed because it is too large Load Diff
+261 -80
View File
@@ -43,15 +43,158 @@
#ifndef STEPPER_H
#define STEPPER_H
#include "MarlinConfig.h"
// Disable multiple steps per ISR
//#define DISABLE_MULTI_STEPPING
//
// Estimate the amount of time the Stepper ISR will take to execute
//
#ifndef MINIMUM_STEPPER_PULSE
#define MINIMUM_STEPPER_PULSE 0UL
#endif
#ifndef MAXIMUM_STEPPER_RATE
#if MINIMUM_STEPPER_PULSE
#define MAXIMUM_STEPPER_RATE (1000000UL / (2UL * (unsigned long)(MINIMUM_STEPPER_PULSE)))
#else
#define MAXIMUM_STEPPER_RATE 500000UL
#endif
#endif
// The base ISR takes 752 cycles
#define ISR_BASE_CYCLES 752UL
// Linear advance base time is 32 cycles
#if ENABLED(LIN_ADVANCE)
#define ISR_LA_BASE_CYCLES 32UL
#else
#define ISR_LA_BASE_CYCLES 0UL
#endif
// S curve interpolation adds 160 cycles
#if ENABLED(S_CURVE_ACCELERATION)
#define ISR_S_CURVE_CYCLES 160UL
#else
#define ISR_S_CURVE_CYCLES 0UL
#endif
// Stepper Loop base cycles
#define ISR_LOOP_BASE_CYCLES 32UL
// To start the step pulse, in the worst case takes
#define ISR_START_STEPPER_CYCLES 57UL
// And each stepper (start + stop pulse) takes in worst case
#define ISR_STEPPER_CYCLES 88UL
// Add time for each stepper
#ifdef HAS_X_STEP
#define ISR_START_X_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
#define ISR_X_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_START_X_STEPPER_CYCLES 0UL
#define ISR_X_STEPPER_CYCLES 0UL
#endif
#ifdef HAS_Y_STEP
#define ISR_START_Y_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
#define ISR_Y_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_START_Y_STEPPER_CYCLES 0UL
#define ISR_Y_STEPPER_CYCLES 0UL
#endif
#ifdef HAS_Z_STEP
#define ISR_START_Z_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
#define ISR_Z_STEPPER_CYCLES ISR_STEPPER_CYCLES
#else
#define ISR_START_Z_STEPPER_CYCLES 0UL
#define ISR_Z_STEPPER_CYCLES 0UL
#endif
// E is always interpolated, even for mixing extruders
#define ISR_START_E_STEPPER_CYCLES ISR_START_STEPPER_CYCLES
#define ISR_E_STEPPER_CYCLES ISR_STEPPER_CYCLES
// If linear advance is disabled, then the loop also handles them
#if DISABLED(LIN_ADVANCE) && ENABLED(MIXING_EXTRUDER)
#define ISR_START_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_START_STEPPER_CYCLES))
#define ISR_MIXING_STEPPER_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
#else
#define ISR_START_MIXING_STEPPER_CYCLES 0UL
#define ISR_MIXING_STEPPER_CYCLES 0UL
#endif
// Calculate the minimum time to start all stepper pulses in the ISR loop
#define MIN_ISR_START_LOOP_CYCLES (ISR_START_X_STEPPER_CYCLES + ISR_START_Y_STEPPER_CYCLES + ISR_START_Z_STEPPER_CYCLES + ISR_START_E_STEPPER_CYCLES + ISR_START_MIXING_STEPPER_CYCLES)
// And the total minimum loop time, not including the base
#define MIN_ISR_LOOP_CYCLES (ISR_X_STEPPER_CYCLES + ISR_Y_STEPPER_CYCLES + ISR_Z_STEPPER_CYCLES + ISR_E_STEPPER_CYCLES + ISR_MIXING_STEPPER_CYCLES)
// Calculate the minimum MPU cycles needed per pulse to enforce, limited to the max stepper rate
#define _MIN_STEPPER_PULSE_CYCLES(N) MAX((unsigned long)((F_CPU) / (MAXIMUM_STEPPER_RATE)), ((F_CPU) / 500000UL) * (N))
#if MINIMUM_STEPPER_PULSE
#define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES((unsigned long)(MINIMUM_STEPPER_PULSE))
#else
#define MIN_STEPPER_PULSE_CYCLES _MIN_STEPPER_PULSE_CYCLES(1UL)
#endif
// Calculate the minimum ticks of the PULSE timer that must elapse with the step pulse enabled
// adding the "start stepper pulse" code section execution cycles to account for that not all
// pulses start at the beginning of the loop, so an extra time must be added to compensate so
// the last generated pulse (usually the extruder stepper) has the right length
#define MIN_PULSE_TICKS (((PULSE_TIMER_TICKS_PER_US) * (unsigned long)(MINIMUM_STEPPER_PULSE)) + ((MIN_ISR_START_LOOP_CYCLES) / (unsigned long)(PULSE_TIMER_PRESCALE)))
// Calculate the extra ticks of the PULSE timer between step pulses
#define ADDED_STEP_TICKS (((MIN_STEPPER_PULSE_CYCLES) / (PULSE_TIMER_PRESCALE)) - (MIN_PULSE_TICKS))
// But the user could be enforcing a minimum time, so the loop time is
#define ISR_LOOP_CYCLES (ISR_LOOP_BASE_CYCLES + MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LOOP_CYCLES))
// If linear advance is enabled, then it is handled separately
#if ENABLED(LIN_ADVANCE)
// Estimate the minimum LA loop time
#if ENABLED(MIXING_EXTRUDER)
#define MIN_ISR_LA_LOOP_CYCLES ((MIXING_STEPPERS) * (ISR_STEPPER_CYCLES))
#else
#define MIN_ISR_LA_LOOP_CYCLES ISR_STEPPER_CYCLES
#endif
// And the real loop time
#define ISR_LA_LOOP_CYCLES MAX(MIN_STEPPER_PULSE_CYCLES, MIN_ISR_LA_LOOP_CYCLES)
#else
#define ISR_LA_LOOP_CYCLES 0UL
#endif
// Now estimate the total ISR execution time in cycles given a step per ISR multiplier
#define ISR_EXECUTION_CYCLES(R) (((ISR_BASE_CYCLES + ISR_S_CURVE_CYCLES + (ISR_LOOP_CYCLES) * (R) + ISR_LA_BASE_CYCLES + ISR_LA_LOOP_CYCLES)) / (R))
// The maximum allowable stepping frequency when doing x128-x1 stepping (in Hz)
#define MAX_STEP_ISR_FREQUENCY_128X ((F_CPU) / ISR_EXECUTION_CYCLES(128))
#define MAX_STEP_ISR_FREQUENCY_64X ((F_CPU) / ISR_EXECUTION_CYCLES(64))
#define MAX_STEP_ISR_FREQUENCY_32X ((F_CPU) / ISR_EXECUTION_CYCLES(32))
#define MAX_STEP_ISR_FREQUENCY_16X ((F_CPU) / ISR_EXECUTION_CYCLES(16))
#define MAX_STEP_ISR_FREQUENCY_8X ((F_CPU) / ISR_EXECUTION_CYCLES(8))
#define MAX_STEP_ISR_FREQUENCY_4X ((F_CPU) / ISR_EXECUTION_CYCLES(4))
#define MAX_STEP_ISR_FREQUENCY_2X ((F_CPU) / ISR_EXECUTION_CYCLES(2))
#define MAX_STEP_ISR_FREQUENCY_1X ((F_CPU) / ISR_EXECUTION_CYCLES(1))
// The minimum allowable frequency for step smoothing will be 1/10 of the maximum nominal frequency (in Hz)
#define MIN_STEP_ISR_FREQUENCY MAX_STEP_ISR_FREQUENCY_1X
//
// Stepper class definition
//
#include "planner.h"
#include "speed_lookuptable.h"
#include "stepper_indirection.h"
#include "language.h"
#include "types.h"
class Stepper;
extern Stepper stepper;
// intRes = intIn1 * intIn2 >> 16
// uses:
// r26 to store 0
@@ -83,10 +226,8 @@ class Stepper {
public:
static block_t* current_block; // A pointer to the block currently being traced
#if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
static bool performing_homing;
static bool homing_dual_axis;
#endif
#if HAS_MOTOR_CURRENT_PWM
@@ -98,26 +239,57 @@ class Stepper {
private:
static block_t* current_block; // A pointer to the block currently being traced
static uint8_t last_direction_bits, // The next stepping-bits to be output
last_movement_extruder, // Last movement extruder, as computed when the last movement was fetched from planner
axis_did_move; // Last Movement in the given direction is not null, as computed when the last movement was fetched from planner
static bool abort_current_block; // Signals to the stepper that current block should be aborted
#if DISABLED(MIXING_EXTRUDER)
static uint8_t last_moved_extruder; // Last-moved extruder, as set when the last movement was fetched from planner
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
static bool locked_x_motor, locked_x2_motor;
static bool locked_X_motor, locked_X2_motor;
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
static bool locked_y_motor, locked_y2_motor;
static bool locked_Y_motor, locked_Y2_motor;
#endif
#if ENABLED(Z_DUAL_ENDSTOPS)
static bool locked_z_motor, locked_z2_motor;
static bool locked_Z_motor, locked_Z2_motor;
#endif
// Counter variables for the Bresenham line tracer
static int32_t counter_X, counter_Y, counter_Z, counter_E;
static uint32_t step_events_completed; // The number of step events executed in the current block
static uint32_t acceleration_time, deceleration_time; // time measured in Stepper Timer ticks
static uint8_t steps_per_isr; // Count of steps to perform per Stepper ISR call
#if ENABLED(BEZIER_JERK_CONTROL)
#if ENABLED(ADAPTIVE_STEP_SMOOTHING)
static uint8_t oversampling_factor; // Oversampling factor (log2(multiplier)) to increase temporal resolution of axis
#else
static constexpr uint8_t oversampling_factor = 0;
#endif
// Delta error variables for the Bresenham line tracer
static int32_t delta_error[XYZE];
static uint32_t advance_dividend[XYZE],
advance_divisor,
step_events_completed, // The number of step events executed in the current block
accelerate_until, // The point from where we need to stop acceleration
decelerate_after, // The point from where we need to start decelerating
step_event_count; // The total event count for the current block
// Mixing extruder mix delta_errors for bresenham tracing
#if ENABLED(MIXING_EXTRUDER)
static int32_t delta_error_m[MIXING_STEPPERS];
static uint32_t advance_dividend_m[MIXING_STEPPERS],
advance_divisor_m;
#define MIXING_STEPPERS_LOOP(VAR) \
for (uint8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++)
#else
static int8_t active_extruder; // Active extruder
#endif
#if ENABLED(S_CURVE_ACCELERATION)
static int32_t bezier_A, // A coefficient in Bézier speed curve
bezier_B, // B coefficient in Bézier speed curve
bezier_C; // C coefficient in Bézier speed curve
@@ -128,33 +300,19 @@ class Stepper {
#endif
static uint32_t nextMainISR; // time remaining for the next Step ISR
static bool all_steps_done; // all steps done
#if ENABLED(LIN_ADVANCE)
static uint32_t LA_decelerate_after; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static uint32_t nextAdvanceISR, eISR_Rate;
static uint16_t current_adv_steps, final_adv_steps, max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static int8_t e_steps;
static bool use_advance_lead;
#if E_STEPPERS > 1
static int8_t LA_active_extruder; // Copy from current executed block. Needed because current_block is set to NULL "too early".
#else
static constexpr int8_t LA_active_extruder = 0;
#endif
static uint32_t nextAdvanceISR, LA_isr_rate;
static uint16_t LA_current_adv_steps, LA_final_adv_steps, LA_max_adv_steps; // Copy from current executed block. Needed because current_block is set to NULL "too early".
static int8_t LA_steps;
static bool LA_use_advance_lead;
#endif // LIN_ADVANCE
static uint32_t acceleration_time, deceleration_time;
static uint8_t step_loops, step_loops_nominal;
static uint32_t ticks_nominal;
#if DISABLED(BEZIER_JERK_CONTROL)
static int32_t ticks_nominal;
#if DISABLED(S_CURVE_ACCELERATION)
static uint32_t acc_step_rate; // needed for deceleration start point
#endif
static volatile int32_t endstops_trigsteps[XYZ];
static volatile int32_t endstops_stepsTotal, endstops_stepsDone;
//
// Positions of stepper motors, in step units
@@ -164,17 +322,7 @@ class Stepper {
//
// 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 int32_t 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
static int8_t count_direction[NUM_AXIS];
public:
@@ -189,7 +337,7 @@ class Stepper {
// Interrupt Service Routines
// The ISR scheduler
static hal_timer_t isr_scheduler();
static void isr();
// The stepper pulse phase ISR
static void stepper_pulse_phase_isr();
@@ -202,6 +350,9 @@ class Stepper {
static uint32_t advance_isr();
#endif
// Check if the given block is busy or not - Must not be called from ISR contexts
static bool is_block_busy(const block_t* const block);
// Get the position of a stepper, in steps
static int32_t position(const AxisEnum axis);
@@ -222,7 +373,15 @@ class Stepper {
FORCE_INLINE static bool axis_is_moving(const AxisEnum axis) { return TEST(axis_did_move, axis); }
// The extruder associated to the last movement
FORCE_INLINE static uint8_t movement_extruder() { return last_movement_extruder; }
FORCE_INLINE static uint8_t movement_extruder() {
return
#if ENABLED(MIXING_EXTRUDER)
0
#else
last_moved_extruder
#endif
;
}
// Handle a triggered endstop
static void endstop_triggered(const AxisEnum axis);
@@ -241,20 +400,20 @@ class Stepper {
static void microstep_readings();
#endif
#if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
FORCE_INLINE static void set_homing_dual_axis(const bool state) { homing_dual_axis = state; }
#endif
#if ENABLED(X_DUAL_ENDSTOPS)
FORCE_INLINE static void set_homing_flag_x(const bool state) { performing_homing = state; }
FORCE_INLINE static void set_x_lock(const bool state) { locked_x_motor = state; }
FORCE_INLINE static void set_x2_lock(const bool state) { locked_x2_motor = state; }
FORCE_INLINE static void set_x_lock(const bool state) { locked_X_motor = state; }
FORCE_INLINE static void set_x2_lock(const bool state) { locked_X2_motor = state; }
#endif
#if ENABLED(Y_DUAL_ENDSTOPS)
FORCE_INLINE static void set_homing_flag_y(const bool state) { performing_homing = state; }
FORCE_INLINE static void set_y_lock(const bool state) { locked_y_motor = state; }
FORCE_INLINE static void set_y2_lock(const bool state) { locked_y2_motor = state; }
FORCE_INLINE static void set_y_lock(const bool state) { locked_Y_motor = state; }
FORCE_INLINE static void set_y2_lock(const bool state) { locked_Y2_motor = state; }
#endif
#if ENABLED(Z_DUAL_ENDSTOPS)
FORCE_INLINE static void set_homing_flag_z(const bool state) { performing_homing = state; }
FORCE_INLINE static void set_z_lock(const bool state) { locked_z_motor = state; }
FORCE_INLINE static void set_z2_lock(const bool state) { locked_z2_motor = state; }
FORCE_INLINE static void set_z_lock(const bool state) { locked_Z_motor = state; }
FORCE_INLINE static void set_z2_lock(const bool state) { locked_Z2_motor = state; }
#endif
#if ENABLED(BABYSTEPPING)
@@ -268,16 +427,21 @@ class Stepper {
// Set the current position in steps
inline static void set_position(const int32_t &a, const int32_t &b, const int32_t &c, const int32_t &e) {
planner.synchronize();
CRITICAL_SECTION_START;
const bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
_set_position(a, b, c, e);
CRITICAL_SECTION_END;
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
}
inline static void set_position(const AxisEnum a, const int32_t &v) {
planner.synchronize();
CRITICAL_SECTION_START;
const bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();
count_position[a] = v;
CRITICAL_SECTION_END;
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();
}
private:
@@ -288,25 +452,42 @@ class Stepper {
// Set direction bits for all steppers
static void set_directions();
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate) {
FORCE_INLINE static uint32_t calc_timer_interval(uint32_t step_rate, uint8_t scale, uint8_t* loops) {
uint32_t timer;
NOMORE(step_rate, uint32_t(MAX_STEP_FREQUENCY));
// Scale the frequency, as requested by the caller
step_rate <<= scale;
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;
}
uint8_t multistep = 1;
#if DISABLED(DISABLE_MULTI_STEPPING)
NOLESS(step_rate, uint32_t(F_CPU / 500000U));
step_rate -= F_CPU / 500000; // Correct for minimal speed
// The stepping frequency limits for each multistepping rate
static const uint32_t limit[] PROGMEM = {
( MAX_STEP_ISR_FREQUENCY_1X ),
( MAX_STEP_ISR_FREQUENCY_2X >> 1),
( MAX_STEP_ISR_FREQUENCY_4X >> 2),
( MAX_STEP_ISR_FREQUENCY_8X >> 3),
( MAX_STEP_ISR_FREQUENCY_16X >> 4),
( MAX_STEP_ISR_FREQUENCY_32X >> 5),
( MAX_STEP_ISR_FREQUENCY_64X >> 6),
(MAX_STEP_ISR_FREQUENCY_128X >> 7)
};
// Select the proper multistepping
uint8_t idx = 0;
while (idx < 7 && step_rate > (uint32_t)pgm_read_dword(&limit[idx])) {
step_rate >>= 1;
multistep <<= 1;
++idx;
};
#else
NOMORE(step_rate, uint32_t(MAX_STEP_ISR_FREQUENCY_1X));
#endif
*loops = multistep;
constexpr uint32_t min_step_rate = F_CPU / 500000U;
NOLESS(step_rate, min_step_rate);
step_rate -= min_step_rate; // Correct for minimal speed
if (step_rate >= (8 * 256)) { // higher step rate
const uint8_t tmp_step_rate = (step_rate & 0x00FF);
const uint16_t table_address = (uint16_t)&speed_lookuptable_fast[(uint8_t)(step_rate >> 8)][0],
@@ -320,15 +501,13 @@ class Stepper {
timer = (uint16_t)pgm_read_word_near(table_address)
- (((uint16_t)pgm_read_word_near(table_address + 2) * (uint8_t)(step_rate & 0x0007)) >> 3);
}
if (timer < 100) { // (20kHz - this should never happen)
timer = 100;
SERIAL_ECHOLNPAIR(MSG_STEPPER_TOO_HIGH, step_rate);
}
// (there is no need to limit the timer value here. All limits have been
// applied above, and AVR is able to keep up at 30khz Stepping ISR rate)
return timer;
}
#if ENABLED(BEZIER_JERK_CONTROL)
#if ENABLED(S_CURVE_ACCELERATION)
static void _calc_bezier_curve_coeffs(const int32_t v0, const int32_t v1, const uint32_t av);
static int32_t _eval_bezier_curve(const uint32_t curr_step);
#endif
@@ -343,4 +522,6 @@ class Stepper {
};
extern Stepper stepper;
#endif // STEPPER_H
+2 -2
View File
@@ -91,8 +91,8 @@
mcp4728_simpleCommand(UPDATE);
}
static float dac_perc(int8_t n) { return 100.0 * mcp4728_getValue(dac_order[n]) * (1.0 / (DAC_STEPPER_MAX)); }
static float dac_amps(int8_t n) { return mcp4728_getDrvPct(dac_order[n]) * (DAC_STEPPER_MAX) * 0.125 * (1.0 / (DAC_STEPPER_SENSE)); }
static float dac_perc(int8_t n) { return 100.0f * mcp4728_getValue(dac_order[n]) * (1.0f / (DAC_STEPPER_MAX)); }
static float dac_amps(int8_t n) { return mcp4728_getDrvPct(dac_order[n]) * (DAC_STEPPER_MAX) * 0.125 * (1.0f / (DAC_STEPPER_SENSE)); }
uint8_t dac_current_get_percent(const AxisEnum axis) { return mcp4728_getDrvPct(dac_order[axis]); }
void dac_current_set_percents(const uint8_t pct[XYZE]) {
+3 -5
View File
@@ -201,8 +201,6 @@
#if ENABLED(HYBRID_THRESHOLD)
st.stealth_max_speed(12650000UL*microsteps/(256*thrs*spmm));
#endif
#elif ENABLED(SENSORLESS_HOMING)
st.coolstep_min_speed(1024UL * 1024UL - 1UL);
#endif
st.GSTAT(); // Clear GSTAT
}
@@ -246,7 +244,7 @@
#if ENABLED(SENSORLESS_HOMING)
#define TMC_INIT_SGT(P,Q) stepper##Q.sgt(P##_HOMING_SENSITIVITY);
#ifdef X_HOMING_SENSITIVITY
#if X_SENSORLESS
#if ENABLED(X_IS_TMC2130) || ENABLED(IS_TRAMS)
stepperX.sgt(X_HOMING_SENSITIVITY);
#endif
@@ -254,7 +252,7 @@
stepperX2.sgt(X_HOMING_SENSITIVITY);
#endif
#endif
#ifdef Y_HOMING_SENSITIVITY
#if Y_SENSORLESS
#if ENABLED(Y_IS_TMC2130) || ENABLED(IS_TRAMS)
stepperY.sgt(Y_HOMING_SENSITIVITY);
#endif
@@ -262,7 +260,7 @@
stepperY2.sgt(Y_HOMING_SENSITIVITY);
#endif
#endif
#ifdef Z_HOMING_SENSITIVITY
#if Z_SENSORLESS
#if ENABLED(Z_IS_TMC2130) || ENABLED(IS_TRAMS)
stepperZ.sgt(Z_HOMING_SENSITIVITY);
#endif

Some files were not shown because too many files have changed in this diff Show More