DerAndere1 / Marlin

Optimized firmware for RepRap 3D printers based on the Arduino platform. The branch Marlin2ForPipetBot is optimized firmware for cartesian robots (lab robots, also known as liquid handling robots or pipetting robots)
https://derandere.gitlab.io/pipetbot-a8
GNU General Public License v3.0
53 stars 20 forks source link

[BUG][bf2_6axis_dev] Axes I, J and K do not move #1

Closed DerAndere1 closed 4 years ago

DerAndere1 commented 5 years ago

Description

With the files from the bf_6axes_dev branch downloaded today, when specifying #define NON_E_AXES = 4 or #define NON_E_AXES = 5 or #define NON_E_AXES = 6 only axes XYZ can be moved by issuing G-code G1.

Steps to Reproduce

  1. Use the original PipetBot-A8 as detailed at https://it-by-derandere.blogspot.com/p/pipetbot-a8.html.
  2. visit https://github.com/DerAndere1/Marlin/tree/bf2_6axis_dev and download the files from that branch.
  3. Copy the content of Marlin/src/config/examples/DerAndere/PipetBot-A8 to Marlin/ and confirm the replacement of the existing files Marlin/Configuration.h and Marlin/Configuration_adv.h
  4. Upload the configured firmware from step 3 to the microcontroller of the PipetBot-A8
  5. Issue G-code command G28 I or G28 or G-code commands like G1 I10 F100 or G1 X5 Y6 Z3 I40 J50 K60 E70 F100 (e.g. via USB serial connection using either printrun or Universal G-code sender (UGS))

Expected behavior: The stepper motors connected to the pins for AXIS_I, AXIS_J, AXIS_K should move similar to those connected to pins for AXIS_X, AXIS_Y and AXIS_Z.

Actual behavior: Only stepper motors connected to the pins for AXIS_X, AXIS_Y and AXIS_Z move. Steppers for I,J and K cannot be moved manually without applying high load. This indicates that these steppers are enabled.

Additional Information

None

vector76 commented 5 years ago

Hello I am interested in this functionality and I am unclear on the current status. I can see multiple branches, the most recent of which was touched in June, but it appears these are intending to get E-axis homing merged into upstream.

I thought I might rebase the main commit from bf2_6axis_dev on to the current Marlin but I am not so fluent in conflict resolution so I might have to work off of the slightly stale bf2_6axis_dev. What should I expect?

My alternative, which might "work" but which I don't like, is to perform CAM with A and B axes and then post-process into a fake mixing extruder, enabling MIXING_EXTRUDER and performing M165 between each movement. I'm not sure if the mix factors can be negative and in any case this would be an ugly approach.

Anyway the main question is, if I were to use this bf2_6axis_dev as a starting point, what should I expect and is there anything else I should know before trying to go forward?

DerAndere1 commented 4 years ago

I never could make it work. This was a toy project for me to learn programming, so I did not research but there is a high chance that 8 bit AVRs are too slow to process more than 4 Axes (including extruder) in parallel. Note that my Idea was to support cartesian robots where I,J,K move additional steppers that do not influence positioning of the tool in any way. If you need support for a specific kinematic model (e.g. 5 axis arm), I don't know how much code you have to add. If you need more than 3 axes for a serious project , currently the best is to base your project on Smoothieware + their supported hardware. Smoothieware has support for 6 axes. Also, check if https://github.com/fra589/grbl-Mega-5X/ meets your requirements. If you still want to add 6 axis support to Marlin, I would first search for all the commits I made and analyze the diff to understand the changes. If you see you can fix the 6axis_dev branch easily, do that in this branch, the merge with current Marlin can be done later by someone else. If you think the fix will be difficult, it will make sense for you to first learn how to resolve conflics during a merge. Use a visual tool to do the conflict resolution (I use Eclipse+Egit). If something goes wrong during the merge, you can always create a new branch that is a clone of my bf2_6axis_dev and try the merge again. To give more feedback, I would need to know what your requirements are: What type of kinematic model? do you need endstops on all axes? do you need auto-homing on all axes? do you have a printer or engraver where extrusion/laser power needs to be calculated based on XYZ-movement speed? Is grbl-Mega-5X enough?

vector76 commented 4 years ago

Thank you for the clarification. I don't really "need" 5-axis, I am mostly curious to play with it. I think I will try 3+2 and postprocess A and B into fake extruder movements. I have no extruder so I have 2 free stepper drivers anyway, and I am wanting to play with 3-axis milling with 2 rotary axes.

I appreciate the work that you put into this. It's definitely a challenge. In the end I think I can achieve my objective with other means.

DerAndere1 commented 4 years ago

If grbl-Mega-5X or Smoothieware is not a solution, Repetier Firmware 2.0 (https://github.com/repetier/Repetier-Firmware/tree/dev2) supports 7 axes and CNC milling tools. It is currently in development but you can already try it on Ardunino Due-based boards.

nguyennhattam268 commented 4 years ago

Hello, I control the axes i, j, k but they run very slowly :-D there is still much work to do too Sorry I'm not good at English

DerAndere1 commented 4 years ago

@nguyennhattam268 Hi, thats great news. Could You send me your source code for inspection? If you don't want to share certain parts of your code, leave those parts out. If you are not familiar with github, you can put the source code into a zip-compressed folder and drag and drop that zip-compressed folder into a comment here.

nguyennhattam268 commented 4 years ago

Yes, I will post here because I am not good at English 2 is that I don't have much time for this because I have to go to work I did 6asix on Repetier_firmware last year but I have to use arduino due and RAMPS_FD I wanted to use ramps1.4 and marlin so I made it with passion This is my test video and I only changed a few parameters in the stepper file the most important is to change LOOP_NUM_AXIS_N in CONFIGRUATION_STORE.CPP https://www.youtube.com/channel/UCnRniVi-9ObhQ87oIsQxihQ?view_as=subscriber

DerAndere1 commented 4 years ago

@nguyennhattam268 Can you copy your stepper.cpp file into a comment here? I would love to mention your name (give attribution to you) and fix 6_axis_dev for everyone.

nguyennhattam268 commented 4 years ago

O of course I will send it right here I could not find any place to download zip files here stepper_indirection.cpp /**

/**

include "stepper_indirection.h"

include "../inc/MarlinConfig.h"

include "stepper.h"

if HAS_DRIVER(L6470)

include "L6470/L6470_Marlin.h"

endif

// // TMC26X Driver objects and inits //

if HAS_DRIVER(TMC26X)

include

ifdef STM32F7

#include "../HAL/HAL_STM32F7/TMC2660.h"

else

#include <TMC26XStepper.h>

endif

define _TMC26X_DEFINE(ST) TMC26XStepper stepper##ST(200, ST##_CS_PIN, ST##_STEP_PIN, ST##_DIR_PIN, ST##_MAX_CURRENT, ST##_SENSE_RESISTOR)

if AXIS_DRIVER_TYPE_X(TMC26X)

_TMC26X_DEFINE(X);

endif

if AXIS_DRIVER_TYPE_X2(TMC26X)

_TMC26X_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE_Y(TMC26X)

_TMC26X_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE_Y2(TMC26X)

_TMC26X_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE_Z(TMC26X)

_TMC26X_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE_Z2(TMC26X)

_TMC26X_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE_Z3(TMC26X)

_TMC26X_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE_E0(TMC26X)

_TMC26X_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE_E1(TMC26X)

_TMC26X_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE_E2(TMC26X)

_TMC26X_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE_E3(TMC26X)

_TMC26X_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE_E4(TMC26X)

_TMC26X_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE_E5(TMC26X)

_TMC26X_DEFINE(E5);

endif

define _TMC26X_INIT(A) do{ \

stepper##A.setMicrosteps(A##_MICROSTEPS); \
stepper##A.start(); \

}while(0)

void tmc26x_init_to_defaults() {

if AXIS_DRIVER_TYPE_X(TMC26X)

  _TMC26X_INIT(X);
#endif
#if AXIS_DRIVER_TYPE_X2(TMC26X)
  _TMC26X_INIT(X2);
#endif
#if AXIS_DRIVER_TYPE_Y(TMC26X)
  _TMC26X_INIT(Y);
#endif
#if AXIS_DRIVER_TYPE_Y2(TMC26X)
  _TMC26X_INIT(Y2);
#endif
#if AXIS_DRIVER_TYPE_Z(TMC26X)
  _TMC26X_INIT(Z);
#endif
#if AXIS_DRIVER_TYPE_Z2(TMC26X)
  _TMC26X_INIT(Z2);
#endif
#if AXIS_DRIVER_TYPE_Z3(TMC26X)
  _TMC26X_INIT(Z3);
#endif
#if AXIS_DRIVER_TYPE_E0(TMC26X)
  _TMC26X_INIT(E0);
#endif
#if AXIS_DRIVER_TYPE_E1(TMC26X)
  _TMC26X_INIT(E1);
#endif
#if AXIS_DRIVER_TYPE_E2(TMC26X)
  _TMC26X_INIT(E2);
#endif
#if AXIS_DRIVER_TYPE_E3(TMC26X)
  _TMC26X_INIT(E3);
#endif
#if AXIS_DRIVER_TYPE_E4(TMC26X)
  _TMC26X_INIT(E4);
#endif
#if AXIS_DRIVER_TYPE_E5(TMC26X)
  _TMC26X_INIT(E5);
#endif

}

endif // TMC26X

if HAS_TRINAMIC

enum StealthIndex : uint8_t { STEALTH_AXIS_XY, STEALTH_AXIS_Z, STEALTH_AXIS_E };

define _TMC_INIT(ST, SPMM_INDEX, STEALTH_INDEX) tmc_init(stepper##ST, ST##_CURRENT, ST##_MICROSTEPS, ST##_HYBRID_THRESHOLD, planner.settings.axis_steps_per_mm[SPMM_INDEX], stealthchop_by_axis[STEALTH_INDEX])

endif

// // TMC2130 Driver objects and inits //

if HAS_DRIVER(TMC2130)

include

include "planner.h"

include "../core/enum.h"

if ENABLED(TMC_USE_SW_SPI)

#define _TMC2130_DEFINE(ST, L) TMCMarlin<TMC2130Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE, TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK)
#define TMC2130_DEFINE(ST) _TMC2130_DEFINE(ST, TMC_##ST##_LABEL)

else

#define _TMC2130_DEFINE(ST, L) TMCMarlin<TMC2130Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE)
#define TMC2130_DEFINE(ST) _TMC2130_DEFINE(ST, TMC_##ST##_LABEL)

endif

// Stepper objects of TMC2130 steppers used

if AXIS_DRIVER_TYPE_X(TMC2130)

TMC2130_DEFINE(X);

endif

if AXIS_DRIVER_TYPE_X2(TMC2130)

TMC2130_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE_Y(TMC2130)

TMC2130_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE_Y2(TMC2130)

TMC2130_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE_Z(TMC2130)

TMC2130_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE_Z2(TMC2130)

TMC2130_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE_Z3(TMC2130)

TMC2130_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE_E0(TMC2130)

TMC2130_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE_E1(TMC2130)

TMC2130_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE_E2(TMC2130)

TMC2130_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE_E3(TMC2130)

TMC2130_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE_E4(TMC2130)

TMC2130_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE_E5(TMC2130)

TMC2130_DEFINE(E5);

endif

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC2130Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t thrs, const float spmm, const bool stealth) { st.begin();

CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current

st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;

PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);

#if ENABLED(HYBRID_THRESHOLD)
  st.TPWMTHRS(12650000UL*microsteps/(256*thrs*spmm));
#else
  UNUSED(thrs);
  UNUSED(spmm);
#endif

st.GSTAT(); // Clear GSTAT

}

endif // TMC2130

// // TMC2160 Driver objects and inits //

if HAS_DRIVER(TMC2160)

include

include "planner.h"

include "../core/enum.h"

if ENABLED(TMC_USE_SW_SPI)

#define _TMC2160_DEFINE(ST, L) TMCMarlin<TMC2160Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE, TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK)
#define TMC2160_DEFINE(ST) _TMC2160_DEFINE(ST, TMC_##ST##_LABEL)

else

#define _TMC2160_DEFINE(ST, L) TMCMarlin<TMC2160Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE)
#define TMC2160_DEFINE(ST) _TMC2160_DEFINE(ST, TMC_##ST##_LABEL)

endif

// Stepper objects of TMC2160 steppers used

if AXIS_DRIVER_TYPE(X, TMC2160)

TMC2160_DEFINE(X);

endif

if AXIS_DRIVER_TYPE(X2, TMC2160)

TMC2160_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE(Y, TMC2160)

TMC2160_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE(Y2, TMC2160)

TMC2160_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE(Z, TMC2160)

TMC2160_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE(Z2, TMC2160)

TMC2160_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE(Z3, TMC2160)

TMC2160_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE(E0, TMC2160)

TMC2160_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE(E1, TMC2160)

TMC2160_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE(E2, TMC2160)

TMC2160_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE(E3, TMC2160)

TMC2160_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE(E4, TMC2160)

TMC2160_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE(E5, TMC2160)

TMC2160_DEFINE(E5);

endif

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC2160Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t thrs, const float spmm, const bool stealth) { st.begin();

static constexpr int8_t timings[] = CHOPPER_TIMING; // Default 4, -2, 1

CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = timings[0];
chopconf.intpol = INTERPOLATE;
chopconf.hend = timings[1] + 3;
chopconf.hstrt = timings[2] - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current
st.TCOOLTHRS(0xFFFFF);

#if ENABLED(ADAPTIVE_CURRENT)
  COOLCONF_t coolconf{0};
  coolconf.semin = INCREASE_CURRENT_THRS;
  coolconf.semax = REDUCE_CURRENT_THRS;
  st.COOLCONF(coolconf.sr);
#endif

st.en_pwm_mode(stealth);

PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);

#if ENABLED(HYBRID_THRESHOLD)
  st.TPWMTHRS(12650000UL*microsteps/(256*thrs*spmm));
#else
  UNUSED(thrs);
  UNUSED(spmm);
#endif

st.GSTAT(); // Clear GSTAT

}

endif // TMC2160

// // TMC2208 Driver objects and inits //

if HAS_DRIVER(TMC2208)

include

include "planner.h"

define _TMC2208_DEFINE_HARDWARE(ST, L) TMCMarlin<TMC2208Stepper, L> stepper##ST(&ST##_HARDWARE_SERIAL, ST##_RSENSE)

define TMC2208_DEFINE_HARDWARE(ST) _TMC2208_DEFINEHARDWARE(ST, TMC##ST##_LABEL)

define _TMC2208_DEFINE_SOFTWARE(ST, L) TMCMarlin<TMC2208Stepper, L> stepper##ST(ST##_SERIAL_RX_PIN, ST##_SERIAL_TX_PIN, ST##_RSENSE, ST##_SERIAL_RX_PIN > -1)

define TMC2208_DEFINE_SOFTWARE(ST) _TMC2208_DEFINESOFTWARE(ST, TMC##ST##_LABEL)

// Stepper objects of TMC2208 steppers used

if AXIS_DRIVER_TYPE_X(TMC2208)

#ifdef X_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(X);
#else
  TMC2208_DEFINE_SOFTWARE(X);
#endif

endif

if AXIS_DRIVER_TYPE_X2(TMC2208)

#ifdef X2_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(X2);
#else
  TMC2208_DEFINE_SOFTWARE(X2);
#endif

endif

if AXIS_DRIVER_TYPE_Y(TMC2208)

#ifdef Y_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(Y);
#else
  TMC2208_DEFINE_SOFTWARE(Y);
#endif

endif

if AXIS_DRIVER_TYPE_Y2(TMC2208)

#ifdef Y2_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(Y2);
#else
  TMC2208_DEFINE_SOFTWARE(Y2);
#endif

endif

if AXIS_DRIVER_TYPE_Z(TMC2208)

#ifdef Z_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(Z);
#else
  TMC2208_DEFINE_SOFTWARE(Z);
#endif

endif

if AXIS_DRIVER_TYPE_Z2(TMC2208)

#ifdef Z2_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(Z2);
#else
  TMC2208_DEFINE_SOFTWARE(Z2);
#endif

endif

if AXIS_DRIVER_TYPE_Z3(TMC2208)

#ifdef Z3_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(Z3);
#else
  TMC2208_DEFINE_SOFTWARE(Z3);
#endif

endif

if AXIS_DRIVER_TYPE_E0(TMC2208)

#ifdef E0_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E0);
#else
  TMC2208_DEFINE_SOFTWARE(E0);
#endif

endif

if AXIS_DRIVER_TYPE_E1(TMC2208)

#ifdef E1_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E1);
#else
  TMC2208_DEFINE_SOFTWARE(E1);
#endif

endif

if AXIS_DRIVER_TYPE_E2(TMC2208)

#ifdef E2_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E2);
#else
  TMC2208_DEFINE_SOFTWARE(E2);
#endif

endif

if AXIS_DRIVER_TYPE_E3(TMC2208)

#ifdef E3_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E3);
#else
  TMC2208_DEFINE_SOFTWARE(E3);
#endif

endif

if AXIS_DRIVER_TYPE_E4(TMC2208)

#ifdef E4_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E4);
#else
  TMC2208_DEFINE_SOFTWARE(E4);
#endif

endif

if AXIS_DRIVER_TYPE_E5(TMC2208)

#ifdef E5_HARDWARE_SERIAL
  TMC2208_DEFINE_HARDWARE(E5);
#else
  TMC2208_DEFINE_SOFTWARE(E5);
#endif

endif

void tmc2208_serial_begin() {

if AXIS_DRIVER_TYPE_X(TMC2208)

  #ifdef X_HARDWARE_SERIAL
    X_HARDWARE_SERIAL.begin(115200);
  #else
    stepperX.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_X2(TMC2208)
  #ifdef X2_HARDWARE_SERIAL
    X2_HARDWARE_SERIAL.begin(115200);
  #else
    stepperX2.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_Y(TMC2208)
  #ifdef Y_HARDWARE_SERIAL
    Y_HARDWARE_SERIAL.begin(115200);
  #else
    stepperY.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_Y2(TMC2208)
  #ifdef Y2_HARDWARE_SERIAL
    Y2_HARDWARE_SERIAL.begin(115200);
  #else
    stepperY2.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_Z(TMC2208)
  #ifdef Z_HARDWARE_SERIAL
    Z_HARDWARE_SERIAL.begin(115200);
  #else
    stepperZ.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_Z2(TMC2208)
  #ifdef Z2_HARDWARE_SERIAL
    Z2_HARDWARE_SERIAL.begin(115200);
  #else
    stepperZ2.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_Z3(TMC2208)
  #ifdef Z3_HARDWARE_SERIAL
    Z3_HARDWARE_SERIAL.begin(115200);
  #else
    stepperZ3.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E0(TMC2208)
  #ifdef E0_HARDWARE_SERIAL
    E0_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE0.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E1(TMC2208)
  #ifdef E1_HARDWARE_SERIAL
    E1_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE1.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E2(TMC2208)
  #ifdef E2_HARDWARE_SERIAL
    E2_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE2.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E3(TMC2208)
  #ifdef E3_HARDWARE_SERIAL
    E3_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE3.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E4(TMC2208)
  #ifdef E4_HARDWARE_SERIAL
    E4_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE4.beginSerial(115200);
  #endif
#endif
#if AXIS_DRIVER_TYPE_E5(TMC2208)
  #ifdef E5_HARDWARE_SERIAL
    E5_HARDWARE_SERIAL.begin(115200);
  #else
    stepperE5.beginSerial(115200);
  #endif
#endif

}

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC2208Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t thrs, const float spmm, const bool stealth) { TMC2208_n::GCONF_t gconf{0}; gconf.pdn_disable = true; // Use UART gconf.mstep_reg_select = true; // Select microsteps with UART gconf.i_scale_analog = false; gconf.en_spreadcycle = !stealth; st.GCONF(gconf.sr); st.stored.stealthChop_enabled = stealth;

TMC2208_n::CHOPCONF_t chopconf{0};
chopconf.tbl = 0b01; // blank_time = 24
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current

TMC2208_n::PWMCONF_t pwmconf{0};
pwmconf.pwm_lim = 12;
pwmconf.pwm_reg = 8;
pwmconf.pwm_autograd = true;
pwmconf.pwm_autoscale = true;
pwmconf.pwm_freq = 0b01;
pwmconf.pwm_grad = 14;
pwmconf.pwm_ofs = 36;
st.PWMCONF(pwmconf.sr);

#if ENABLED(HYBRID_THRESHOLD)
  st.TPWMTHRS(12650000UL*microsteps/(256*thrs*spmm));
#else
  UNUSED(thrs);
  UNUSED(spmm);
#endif

st.GSTAT(0b111); // Clear
delay(200);

}

endif // TMC2208

// // TMC2660 Driver objects and inits //

if HAS_DRIVER(TMC2660)

include

include "planner.h"

include "../core/enum.h"

if ENABLED(TMC_USE_SW_SPI)

#define _TMC2660_DEFINE(ST, L) TMCMarlin<TMC2660Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE, TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK)
#define TMC2660_DEFINE(ST) _TMC2660_DEFINE(ST, TMC_##ST##_LABEL)

else

#define _TMC2660_DEFINE(ST, L) TMCMarlin<TMC2660Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE)
#define TMC2660_DEFINE(ST) _TMC2660_DEFINE(ST, TMC_##ST##_LABEL)

endif

// Stepper objects of TMC2660 steppers used

if AXIS_DRIVER_TYPE_X(TMC2660)

TMC2660_DEFINE(X);

endif

if AXIS_DRIVER_TYPE_X2(TMC2660)

TMC2660_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE_Y(TMC2660)

TMC2660_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE_Y2(TMC2660)

TMC2660_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE_Z(TMC2660)

TMC2660_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE_Z2(TMC2660)

TMC2660_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE_E0(TMC2660)

TMC2660_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE_E1(TMC2660)

TMC2660_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE_E2(TMC2660)

TMC2660_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE_E3(TMC2660)

TMC2660_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE_E4(TMC2660)

TMC2660_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE_E5(TMC2660)

TMC2660_DEFINE(E5);

endif

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC2660Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t, const float, const bool) { st.begin();

TMC2660_n::CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA);
st.microsteps(microsteps);
st.intpol(INTERPOLATE);
st.diss2g(true); // Disable short to ground protection. Too many false readings?

#if ENABLED(TMC_DEBUG)
  st.rdsel(0b01);
#endif

}

endif // TMC2660

// // TMC5130 Driver objects and inits //

if HAS_DRIVER(TMC5130)

include

include "planner.h"

include "../core/enum.h"

if ENABLED(TMC_USE_SW_SPI)

#define _TMC5130_DEFINE(ST, L) TMCMarlin<TMC5130Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE, TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK)
#define TMC5130_DEFINE(ST) _TMC5130_DEFINE(ST, TMC_##ST##_LABEL)

else

#define _TMC5130_DEFINE(ST, L) TMCMarlin<TMC5130Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE)
#define TMC5130_DEFINE(ST) _TMC5130_DEFINE(ST, TMC_##ST##_LABEL)

endif

// Stepper objects of TMC5130 steppers used

if AXIS_DRIVER_TYPE_X(TMC5130)

TMC5130_DEFINE(X);

endif

if AXIS_DRIVER_TYPE_X2(TMC5130)

TMC5130_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE_Y(TMC5130)

TMC5130_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE_Y2(TMC5130)

TMC5130_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE_Z(TMC5130)

TMC5130_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE_Z2(TMC5130)

TMC5130_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE_Z3(TMC5130)

TMC5130_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE_E0(TMC5130)

TMC5130_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE_E1(TMC5130)

TMC5130_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE_E2(TMC5130)

TMC5130_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE_E3(TMC5130)

TMC5130_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE_E4(TMC5130)

TMC5130_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE_E5(TMC5130)

TMC5130_DEFINE(E5);

endif

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC5130Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t thrs, const float spmm, const bool stealth) { st.begin();

CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = chopper_timing.toff;
chopconf.intpol = INTERPOLATE;
chopconf.hend = chopper_timing.hend + 3;
chopconf.hstrt = chopper_timing.hstrt - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current

st.en_pwm_mode(stealth);
st.stored.stealthChop_enabled = stealth;

PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);

#if ENABLED(HYBRID_THRESHOLD)
  st.TPWMTHRS(12650000UL*microsteps/(256*thrs*spmm));
#else
  UNUSED(thrs);
  UNUSED(spmm);
#endif

st.GSTAT(); // Clear GSTAT

}

endif // TMC5130

// // TMC5160 Driver objects and inits //

if HAS_DRIVER(TMC5160)

include

include "planner.h"

include "../core/enum.h"

if ENABLED(TMC_USE_SW_SPI)

#define _TMC5160_DEFINE(ST, L) TMCMarlin<TMC5160Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE, TMC_SW_MOSI, TMC_SW_MISO, TMC_SW_SCK)
#define TMC5160_DEFINE(ST) _TMC5160_DEFINE(ST, TMC_##ST##_LABEL)

else

#define _TMC5160_DEFINE(ST, L) TMCMarlin<TMC5160Stepper, L> stepper##ST(ST##_CS_PIN, ST##_RSENSE)
#define TMC5160_DEFINE(ST) _TMC5160_DEFINE(ST, TMC_##ST##_LABEL)

endif

// Stepper objects of TMC5160 steppers used

if AXIS_DRIVER_TYPE(X, TMC5160)

TMC5160_DEFINE(X);

endif

if AXIS_DRIVER_TYPE(X2, TMC5160)

TMC5160_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE(Y, TMC5160)

TMC5160_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE(Y2, TMC5160)

TMC5160_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE(Z, TMC5160)

TMC5160_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE(Z2, TMC5160)

TMC5160_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE(Z3, TMC5160)

TMC5160_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE(E0, TMC5160)

TMC5160_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE(E1, TMC5160)

TMC5160_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE(E2, TMC5160)

TMC5160_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE(E3, TMC5160)

TMC5160_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE(E4, TMC5160)

TMC5160_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE(E5, TMC5160)

TMC5160_DEFINE(E5);

endif

template<char AXIS_LETTER, char DRIVER_ID> void tmc_init(TMCMarlin<TMC5160Stepper, AXIS_LETTER, DRIVER_ID> &st, const uint16_t mA, const uint16_t microsteps, const uint32_t thrs, const float spmm, const bool stealth) { st.begin();

int8_t timings[] = CHOPPER_TIMING; // Default 4, -2, 1

CHOPCONF_t chopconf{0};
chopconf.tbl = 1;
chopconf.toff = timings[0];
chopconf.intpol = INTERPOLATE;
chopconf.hend = timings[1] + 3;
chopconf.hstrt = timings[2] - 1;
st.CHOPCONF(chopconf.sr);

st.rms_current(mA, HOLD_MULTIPLIER);
st.microsteps(microsteps);
st.iholddelay(10);
st.TPOWERDOWN(128); // ~2s until driver lowers to hold current

#if ENABLED(ADAPTIVE_CURRENT)
  COOLCONF_t coolconf{0};
  coolconf.semin = INCREASE_CURRENT_THRS;
  coolconf.semax = REDUCE_CURRENT_THRS;
  st.COOLCONF(coolconf.sr);
#endif

st.en_pwm_mode(stealth);

PWMCONF_t pwmconf{0};
pwmconf.pwm_freq = 0b01; // f_pwm = 2/683 f_clk
pwmconf.pwm_autoscale = true;
pwmconf.pwm_grad = 5;
pwmconf.pwm_ampl = 180;
st.PWMCONF(pwmconf.sr);

#if ENABLED(HYBRID_THRESHOLD)
  st.TPWMTHRS(12650000UL*microsteps/(256*thrs*spmm));
#else
  UNUSED(thrs);
  UNUSED(spmm);
#endif
st.GSTAT(); // Clear GSTAT

}

endif // TMC5160

void restore_stepper_drivers() {

if AXIS_IS_TMC(X)

stepperX.push();

endif

if AXIS_IS_TMC(X2)

stepperX2.push();

endif

if AXIS_IS_TMC(Y)

stepperY.push();

endif

if AXIS_IS_TMC(Y2)

stepperY2.push();

endif

 #if NON_E_AXES > 3
     #if AXIS_IS_TMC(I)
       stepperI.push();
     #endif
      #if NON_E_AXES > 4
        #if AXIS_IS_TMC(J)
          stepperJ.push();
        #endif
       #if NON_E_AXES > 5
        #if AXIS_IS_TMC(K)
          stepperK.push();
        #endif
       #endif
      #endif
    #endif

if AXIS_IS_TMC(Z)

stepperZ.push();

endif

if AXIS_IS_TMC(Z2)

stepperZ2.push();

endif

if AXIS_IS_TMC(Z3)

stepperZ3.push();

endif

if AXIS_IS_TMC(E0)

stepperE0.push();

endif

if AXIS_IS_TMC(E1)

stepperE1.push();

endif

if AXIS_IS_TMC(E2)

stepperE2.push();

endif

if AXIS_IS_TMC(E3)

stepperE3.push();

endif

if AXIS_IS_TMC(E4)

stepperE4.push();

endif

if AXIS_IS_TMC(E5)

stepperE5.push();

endif

}

void reset_stepper_drivers() {

if HAS_DRIVER(TMC26X)

tmc26x_init_to_defaults();

endif

if HAS_DRIVER(L6470)

L6470.init_to_defaults();

endif

if HAS_TRINAMIC

static constexpr bool stealthchop_by_axis[] = {
  #if ENABLED(STEALTHCHOP_XY)
    true
  #else
    false
  #endif
  ,
  #if ENABLED(STEALTHCHOP_Z)
    true
  #else
    false
  #endif
  ,
  #if ENABLED(STEALTHCHOP_E)
    true
  #else
    false
  #endif
};

endif

if AXIS_IS_TMC(X)

_TMC_INIT(X, X_AXIS, STEALTH_AXIS_XY);

endif

if AXIS_IS_TMC(X2)

_TMC_INIT(X2, X_AXIS, STEALTH_AXIS_XY);

endif

if AXIS_IS_TMC(Y)

_TMC_INIT(Y, Y_AXIS, STEALTH_AXIS_XY);

endif

if AXIS_IS_TMC(Y2)

_TMC_INIT(Y2, Y_AXIS, STEALTH_AXIS_XY);

endif

if NON_E_AXES > 3

     #if AXIS_IS_TMC(Y2)
        _TMC_INIT(I, I_AXIS, STEALTH_AXIS_XY);
     #endif
      #if NON_E_AXES > 4
         #if AXIS_IS_TMC(Y2)
        _TMC_INIT(J, J_AXIS, STEALTH_AXIS_XY);
         #endif
       #if NON_E_AXES > 5
        #if AXIS_IS_TMC(Y2)
        _TMC_INIT(K, K_AXIS, STEALTH_AXIS_XY);
         #endif
        #endif
       #endif
      #endif

if AXIS_IS_TMC(Z)

_TMC_INIT(Z, Z_AXIS, STEALTH_AXIS_Z);

endif

if AXIS_IS_TMC(Z2)

_TMC_INIT(Z2, Z_AXIS, STEALTH_AXIS_Z);

endif

if AXIS_IS_TMC(Z3)

_TMC_INIT(Z3, Z_AXIS, STEALTH_AXIS_Z);

endif

if AXIS_IS_TMC(E0)

_TMC_INIT(E0, E_AXIS, STEALTH_AXIS_E);

endif

if AXIS_IS_TMC(E1)

_TMC_INIT(E1, E_AXIS_N(1), STEALTH_AXIS_E);

endif

if AXIS_IS_TMC(E2)

_TMC_INIT(E2, E_AXIS_N(2), STEALTH_AXIS_E);

endif

if AXIS_IS_TMC(E3)

_TMC_INIT(E3, E_AXIS_N(3), STEALTH_AXIS_E);

endif

if AXIS_IS_TMC(E4)

_TMC_INIT(E4, E_AXIS_N(4), STEALTH_AXIS_E);

endif

if AXIS_IS_TMC(E5)

_TMC_INIT(E5, E_AXIS_N(5), STEALTH_AXIS_E);

endif

if USE_SENSORLESS

#if X_SENSORLESS
  #if AXIS_HAS_STALLGUARD(X)
    stepperX.sgt(X_STALL_SENSITIVITY);
  #endif
  #if AXIS_HAS_STALLGUARD(X2)
    stepperX2.sgt(X_STALL_SENSITIVITY);
  #endif
#endif
#if Y_SENSORLESS
  #if AXIS_HAS_STALLGUARD(Y)
    stepperY.sgt(Y_STALL_SENSITIVITY);
  #endif
  #if AXIS_HAS_STALLGUARD(Y2)
    stepperY2.sgt(Y_STALL_SENSITIVITY);
  #endif
#endif
#if Z_SENSORLESS
  #if AXIS_HAS_STALLGUARD(Z)
    stepperZ.sgt(Z_STALL_SENSITIVITY);
  #endif
  #if AXIS_HAS_STALLGUARD(Z2)
    stepperZ2.sgt(Z_STALL_SENSITIVITY);
  #endif
  #if AXIS_HAS_STALLGUARD(Z3)
    stepperZ3.sgt(Z_STALL_SENSITIVITY);
  #endif
#endif

endif

ifdef TMC_ADV

TMC_ADV()

endif

if HAS_TRINAMIC

stepper.set_directions();

endif

}

// // L6470 Driver objects and inits //

if HAS_DRIVER(L6470)

// create stepper objects

define _L6470_DEFINE(ST) L6470 stepper##ST((const int)L6470_CHAIN_SS_PIN)

// L6470 Stepper objects

if AXIS_DRIVER_TYPE_X(L6470)

_L6470_DEFINE(X);

endif

if AXIS_DRIVER_TYPE_X2(L6470)

_L6470_DEFINE(X2);

endif

if AXIS_DRIVER_TYPE_Y(L6470)

_L6470_DEFINE(Y);

endif

if AXIS_DRIVER_TYPE_Y2(L6470)

_L6470_DEFINE(Y2);

endif

if AXIS_DRIVER_TYPE_Z(L6470)

_L6470_DEFINE(Z);

endif

if AXIS_DRIVER_TYPE_Z2(L6470)

_L6470_DEFINE(Z2);

endif

if AXIS_DRIVER_TYPE_Z3(L6470)

_L6470_DEFINE(Z3);

endif

if AXIS_DRIVER_TYPE_E0(L6470)

_L6470_DEFINE(E0);

endif

if AXIS_DRIVER_TYPE_E1(L6470)

_L6470_DEFINE(E1);

endif

if AXIS_DRIVER_TYPE_E2(L6470)

_L6470_DEFINE(E2);

endif

if AXIS_DRIVER_TYPE_E3(L6470)

_L6470_DEFINE(E3);

endif

if AXIS_DRIVER_TYPE_E4(L6470)

_L6470_DEFINE(E4);

endif

if AXIS_DRIVER_TYPE_E5(L6470)

_L6470_DEFINE(E5);

endif

// not using L6470 library's init command because it // briefly sends power to the steppers

define _L6470_INIT_CHIP(Q) do{ \

stepper##Q.resetDev();                                    \
stepper##Q.softFree();                                    \
stepper##Q.SetParam(L6470_CONFIG, CONFIG_PWM_DIV_1        \
                                | CONFIG_PWM_MUL_2        \
                                | CONFIG_SR_290V_us       \
                                | CONFIG_OC_SD_DISABLE    \
                                | CONFIG_VS_COMP_DISABLE  \
                                | CONFIG_SW_HARD_STOP     \
                                | CONFIG_INT_16MHZ);      \
stepper##Q.SetParam(L6470_KVAL_RUN, 0xFF);                \
stepper##Q.SetParam(L6470_KVAL_ACC, 0xFF);                \
stepper##Q.SetParam(L6470_KVAL_DEC, 0xFF);                \
stepper##Q.setMicroSteps(Q##_MICROSTEPS);                 \
stepper##Q.setOverCurrent(Q##_OVERCURRENT);               \
stepper##Q.setStallCurrent(Q##_STALLCURRENT);             \
stepper##Q.SetParam(L6470_KVAL_HOLD, Q##_MAX_VOLTAGE);    \
stepper##Q.SetParam(L6470_ABS_POS, 0);                    \
stepper##Q.getStatus();                                   \

}while(0)

void L6470_Marlin::init_to_defaults() {

if AXIS_DRIVER_TYPE_X(L6470)

  _L6470_INIT_CHIP(X);
#endif
#if AXIS_DRIVER_TYPE_X2(L6470)
  _L6470_INIT_CHIP(X2);
#endif
#if AXIS_DRIVER_TYPE_Y(L6470)
  _L6470_INIT_CHIP(Y);
#endif
#if AXIS_DRIVER_TYPE_Y2(L6470)
  _L6470_INIT_CHIP(Y2);
#endif
#if AXIS_DRIVER_TYPE_Z(L6470)
  _L6470_INIT_CHIP(Z);
#endif
#if AXIS_DRIVER_TYPE_Z2(L6470)
  _L6470_INIT_CHIP(Z2);
#endif
#if AXIS_DRIVER_TYPE_Z3(L6470)
  _L6470_INIT_CHIP(Z3);
#endif
#if AXIS_DRIVER_TYPE_E0(L6470)
  _L6470_INIT_CHIP(E0);
#endif
#if AXIS_DRIVER_TYPE_E1(L6470)
  _L6470_INIT_CHIP(E1);
#endif
#if AXIS_DRIVER_TYPE_E2(L6470)
  _L6470_INIT_CHIP(E2);
#endif
#if AXIS_DRIVER_TYPE_E3(L6470)
  _L6470_INIT_CHIP(E3);
#endif
#if AXIS_DRIVER_TYPE_E4(L6470)
  _L6470_INIT_CHIP(E4);
#endif
#if AXIS_DRIVER_TYPE_E5(L6470)
  _L6470_INIT_CHIP(E5);
#endif

}

endif // L6470

nguyennhattam268 commented 4 years ago

stepper.cpp

include "stepper.h"

Stepper stepper; // Singleton

ifdef AVR

include "speed_lookuptable.h"

endif

include "endstops.h"

include "planner.h"

include "motion.h"

include "../core/macros.h"

include "temperature.h"

include "../lcd/ultralcd.h"

include "../core/language.h"

include "../gcode/queue.h"

include "../sd/cardreader.h"

include "../Marlin.h"

include "../HAL/shared/Delay.h"

if MB(ALLIGATOR)

include "../feature/dac/dac_dac084s085.h"

endif

if HAS_DIGIPOTSS

include

endif

if ENABLED(MIXING_EXTRUDER)

include "../feature/mixing.h"

endif

if FILAMENT_RUNOUT_DISTANCE_MM > 0

include "../feature/runout.h"

endif

if HAS_DRIVER(L6470)

include "../libs/L6470/L6470_Marlin.h"

endif

// public:

if HAS_EXTRA_ENDSTOPS || ENABLED(Z_STEPPER_AUTO_ALIGN)

bool Stepper::separate_multi_axis = false;

endif

if HAS_MOTOR_CURRENT_PWM

uint32_t Stepper::motor_current_setting[3]; // Initialized by settings.load()

endif

// private:

block_t* Stepper::current_block; // (= NULL) A pointer to the block currently being traced Một con trỏ tới khối hiện đang được theo dõi

uint8_t Stepper::last_direction_bits, // = 0 Stepper::axis_did_move; // = 0

bool Stepper::abort_current_block;

if DISABLED(MIXING_EXTRUDER) && EXTRUDERS > 1

uint8_t Stepper::last_moved_extruder = 0xFF;

endif

if ENABLED(X_DUAL_ENDSTOPS)

bool Stepper::locked_X_motor = false, Stepper::locked_X2_motor = false;

endif

if ENABLED(Y_DUAL_ENDSTOPS)

bool Stepper::locked_Y_motor = false, Stepper::locked_Y2_motor = false;

endif

if Z_MULTI_ENDSTOPS || ENABLED(Z_STEPPER_AUTO_ALIGN)

bool Stepper::locked_Z_motor = false, Stepper::locked_Z2_motor = false;

endif

if I_MULTI_ENDSTOPS || ENABLED(Z_STEPPER_AUTO_ALIGN)

bool Stepper::locked_I_motor = false, Stepper::locked_I2_motor = false;

endif

if J_MULTI_ENDSTOPS || ENABLED(J_STEPPER_AUTO_ALIGN)

bool Stepper::locked_J_motor = false, Stepper::locked_J2_motor = false;

endif

if K_MULTI_ENDSTOPS || ENABLED(K_STEPPER_AUTO_ALIGN)

bool Stepper::locked_K_motor = false, Stepper::locked_K2_motor = false;

endif

if ENABLED(Z_TRIPLE_ENDSTOPS) || (ENABLED(Z_STEPPER_AUTO_ALIGN) && ENABLED(Z_TRIPLE_STEPPER_DRIVERS))

bool Stepper::locked_Z3_motor = false;

endif

uint32_t Stepper::acceleration_time, Stepper::deceleration_time; uint8_t Stepper::steps_per_isr;

if DISABLED(ADAPTIVE_STEP_SMOOTHING)

constexpr

endif

uint8_t Stepper::oversampling_factor;

int32_t Stepper::delta_error[NUM_AXIS] = { 0 };

uint32_t Stepper::advance_dividend[NUM_AXIS] = { 0 }, Stepper::advance_divisor = 0, Stepper::step_events_completed = 0, // The number of step events executed in the current block Stepper::accelerate_until, // The point from where we need to stop acceleration Stepper::decelerate_after, // The point from where we need to start decelerating Stepper::step_event_count; // The total event count for the current block

if EXTRUDERS > 1 || ENABLED(MIXING_EXTRUDER)

uint8_t Stepper::stepper_extruder;

else

constexpr uint8_t Stepper::stepper_extruder;

endif

if ENABLED(S_CURVE_ACCELERATION)

int32_t attribute((used)) Stepper::bezier_A asm("bezier_A"); // A coefficient in Bézier speed curve with alias for assembler int32_t attribute((used)) Stepper::bezier_B asm("bezier_B"); // B coefficient in Bézier speed curve with alias for assembler int32_t attribute((used)) Stepper::bezier_C asm("bezier_C"); // C coefficient in Bézier speed curve with alias for assembler uint32_t attribute((used)) Stepper::bezier_F asm("bezier_F"); // F coefficient in Bézier speed curve with alias for assembler uint32_t attribute((used)) Stepper::bezier_AV asm("bezier_AV"); // AV coefficient in Bézier speed curve with alias for assembler

ifdef AVR

bool __attribute__((used)) Stepper::A_negative __asm__("A_negative"); // If A coefficient was negative

endif

bool Stepper::bezier_2nd_half; // =false If Bézier curve has been initialized or not

endif

uint32_t Stepper::nextMainISR = 0;

if ENABLED(LIN_ADVANCE)

constexpr uint32_t LA_ADV_NEVER = 0xFFFFFFFF; uint32_t Stepper::nextAdvanceISR = LA_ADV_NEVER, Stepper::LA_isr_rate = LA_ADV_NEVER; uint16_t Stepper::LA_current_adv_steps = 0, Stepper::LA_final_adv_steps, Stepper::LA_max_adv_steps;

int8_t Stepper::LA_steps = 0;

bool Stepper::LA_use_advance_lead;

endif // LIN_ADVANCE

int32_t Stepper::ticks_nominal = -1;

if DISABLED(S_CURVE_ACCELERATION)

uint32_t Stepper::acc_step_rate; // needed for deceleration start point

endif

volatile int32_t Stepper::endstops_trigsteps[NON_E_AXES];

volatile int32_t Stepper::count_position[NUM_AXIS] = { 0 }; int8_t Stepper::count_direction[NUM_AXIS] = { 0 };

define DUAL_ENDSTOP_APPLY_STEP(A,V) \

if (separate_multi_axis) { \ if (A##_HOME_DIR < 0) { \ if (!(TEST(endstops.state(), A##_MIN) && count_direction[AXIS(A)] < 0) && !locked##A##_motor) A##_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##2_MIN) && count_direction[AXIS(A)] < 0) && !locked##A##2_motor) A##2_STEP_WRITE(V); \ } \ else { \ if (!(TEST(endstops.state(), A##_MAX) && count_direction[AXIS(A)] > 0) && !locked##A##_motor) A##_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##2_MAX) && count_direction[AXIS(A)] > 0) && !locked##A##2_motor) A##2_STEP_WRITE(V); \ } \ } \ else { \ A##_STEP_WRITE(V); \ A##2_STEP_WRITE(V); \ }

define DUAL_SEPARATE_APPLY_STEP(A,V) \

if (separate_multiaxis) { \ if (!locked##A##_motor) A##_STEPWRITE(V); \ if (!locked##A##2_motor) A##2_STEP_WRITE(V); \ } \ else { \ A##_STEP_WRITE(V); \ A##2_STEP_WRITE(V); \ }

define TRIPLE_ENDSTOP_APPLY_STEP(A,V) \

if (separate_multi_axis) { \ if (A##_HOME_DIR < 0) { \ if (!(TEST(endstops.state(), A##_MIN) && count_direction[AXIS(A)] < 0) && !locked##A##_motor) A##_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##2_MIN) && count_direction[AXIS(A)] < 0) && !locked##A##2_motor) A##2_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##3_MIN) && count_direction[AXIS(A)] < 0) && !locked##A##3_motor) A##3_STEP_WRITE(V); \ } \ else { \ if (!(TEST(endstops.state(), A##_MAX) && count_direction[AXIS(A)] > 0) && !locked##A##_motor) A##_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##2_MAX) && count_direction[AXIS(A)] > 0) && !locked##A##2_motor) A##2_STEP_WRITE(V); \ if (!(TEST(endstops.state(), A##3_MAX) && count_direction[AXIS(A)] > 0) && !locked##A##3_motor) A##3_STEP_WRITE(V); \ } \ } \ else { \ A##_STEP_WRITE(V); \ A##2_STEP_WRITE(V); \ A##3_STEP_WRITE(V); \ }

define TRIPLE_SEPARATE_APPLY_STEP(A,V) \

if (separate_multiaxis) { \ if (!locked##A##_motor) A##_STEPWRITE(V); \ if (!locked##A##2_motor) A##2_STEPWRITE(V); \ if (!locked##A##3_motor) A##3_STEP_WRITE(V); \ } \ else { \ A##_STEP_WRITE(V); \ A##2_STEP_WRITE(V); \ A##3_STEP_WRITE(V); \ }

if ENABLED(X_DUAL_STEPPER_DRIVERS)

define X_APPLY_DIR(v,Q) do{ X_DIR_WRITE(v); X2_DIR_WRITE((v) != INVERT_X2_VS_X_DIR); }while(0)

if ENABLED(X_DUAL_ENDSTOPS)

#define X_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(X,v)

else

#define X_APPLY_STEP(v,Q) do{ X_STEP_WRITE(v); X2_STEP_WRITE(v); }while(0)

endif

elif ENABLED(DUAL_X_CARRIAGE)

define X_APPLY_DIR(v,ALWAYS) \

if (extruder_duplication_enabled || ALWAYS) { \
  X_DIR_WRITE(v); \
  X2_DIR_WRITE(v); \
} \
else { \
  if (movement_extruder()) X2_DIR_WRITE(v); else X_DIR_WRITE(v); \
}

define X_APPLY_STEP(v,ALWAYS) \

if (extruder_duplication_enabled || ALWAYS) { \
  X_STEP_WRITE(v); \
  X2_STEP_WRITE(v); \
} \
else { \
  if (movement_extruder()) X2_STEP_WRITE(v); else X_STEP_WRITE(v); \
}

else

define X_APPLY_DIR(v,Q) X_DIR_WRITE(v)

define X_APPLY_STEP(v,Q) X_STEP_WRITE(v)

endif

if ENABLED(Y_DUAL_STEPPER_DRIVERS)

define Y_APPLY_DIR(v,Q) do{ Y_DIR_WRITE(v); Y2_DIR_WRITE((v) != INVERT_Y2_VS_Y_DIR); }while(0)

if ENABLED(Y_DUAL_ENDSTOPS)

#define Y_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Y,v)

else

#define Y_APPLY_STEP(v,Q) do{ Y_STEP_WRITE(v); Y2_STEP_WRITE(v); }while(0)

endif

else

define Y_APPLY_DIR(v,Q) Y_DIR_WRITE(v)

define Y_APPLY_STEP(v,Q) Y_STEP_WRITE(v)

endif

if ENABLED(Z_TRIPLE_STEPPER_DRIVERS)

define Z_APPLY_DIR(v,Q) do{ Z_DIR_WRITE(v); Z2_DIR_WRITE(v); Z3_DIR_WRITE(v); }while(0)

if ENABLED(Z_TRIPLE_ENDSTOPS)

#define Z_APPLY_STEP(v,Q) TRIPLE_ENDSTOP_APPLY_STEP(Z,v)

elif ENABLED(Z_STEPPER_AUTO_ALIGN)

#define Z_APPLY_STEP(v,Q) TRIPLE_SEPARATE_APPLY_STEP(Z,v)

else

#define Z_APPLY_STEP(v,Q) do{ Z_STEP_WRITE(v); Z2_STEP_WRITE(v); Z3_STEP_WRITE(v); }while(0)

endif

elif ENABLED(Z_DUAL_STEPPER_DRIVERS)

define Z_APPLY_DIR(v,Q) do{ Z_DIR_WRITE(v); Z2_DIR_WRITE(v); }while(0)

if ENABLED(Z_DUAL_ENDSTOPS)

#define Z_APPLY_STEP(v,Q) DUAL_ENDSTOP_APPLY_STEP(Z,v)

elif ENABLED(Z_STEPPER_AUTO_ALIGN)

#define Z_APPLY_STEP(v,Q) DUAL_SEPARATE_APPLY_STEP(Z,v)

else

#define Z_APPLY_STEP(v,Q) do{ Z_STEP_WRITE(v); Z2_STEP_WRITE(v); }while(0)

endif

else

define Z_APPLY_DIR(v,Q) Z_DIR_WRITE(v)

define Z_APPLY_STEP(v,Q) Z_STEP_WRITE(v)

endif

if NON_E_AXES > 3

define I_APPLY_DIR(v,Q) I_DIR_WRITE(v)

define I_APPLY_STEP(v,Q) I_STEP_WRITE(v)

if NON_E_AXES > 4

#define J_APPLY_DIR(v,Q) J_DIR_WRITE(v)
#define J_APPLY_STEP(v,Q) J_STEP_WRITE(v)
#if NON_E_AXES > 5
  #define K_APPLY_DIR(v,Q) K_DIR_WRITE(v)
  #define K_APPLY_STEP(v,Q) K_STEP_WRITE(v)
#endif

endif

endif

if DISABLED(MIXING_EXTRUDER)

define E_APPLY_STEP(v,Q) E_STEP_WRITE(stepper_extruder, v)

endif

void Stepper::wake_up() { // TCNT1 = 0; ENABLE_STEPPER_DRIVER_INTERRUPT(); }

/**

if HAS_I_DIR

SET_STEP_DIR(I); // I

endif

if HAS_J_DIR

SET_STEP_DIR(J); // J

endif

if HAS_K_DIR

SET_STEP_DIR(K); // K

endif

if DISABLED(LIN_ADVANCE)

#if ENABLED(MIXING_EXTRUDER)
   // Because this is valid for the whole block we don't know
   // what e-steppers will step. Likely all. Set all.
  if (motor_direction(E_AXIS)) {
    MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
    count_direction[E_AXIS] = -1;
  }
  else {
    MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
    count_direction[E_AXIS] = 1;
  }
#else
  if (motor_direction(E_AXIS)) {
    REV_E_DIR(stepper_extruder);
    count_direction[E_AXIS] = -1;
  }
  else {
    NORM_E_DIR(stepper_extruder);
    count_direction[E_AXIS] = 1;
  }
#endif

endif // !LIN_ADVANCE

if HAS_DRIVER(L6470)

if (L6470.spi_active) {
  L6470.spi_abort = true;                     // interrupted a SPI transfer - need to shut it down gracefully
  for (uint8_t j = 1; j <= L6470::chain[0]; j++)
    L6470_buf[j] = dSPIN_NOP;                 // fill buffer with NOOP commands
  L6470.transfer(L6470_buf, L6470::chain[0]);  // send enough NOOPs to complete any command
  L6470.transfer(L6470_buf, L6470::chain[0]);
  L6470.transfer(L6470_buf, L6470::chain[0]);
}

// The L6470.dir_commands[] array holds the direction command for each stepper

//scan command array and copy matches into L6470.transfer
for (uint8_t j = 1; j <= L6470::chain[0]; j++)
  L6470_buf[j] = L6470.dir_commands[L6470::chain[j]];

L6470.transfer(L6470_buf, L6470::chain[0]);  // send the command stream to the drivers

endif

// A small delay may be needed after changing direction

if MINIMUM_STEPPER_DIR_DELAY > 0

DELAY_NS(MINIMUM_STEPPER_DIR_DELAY);

endif

}

if ENABLED(S_CURVE_ACCELERATION)

/**

/**

HAL_STEP_TIMER_ISR { HAL_timer_isr_prologue(STEP_TIMER_NUM);

Stepper::isr();

HAL_timer_isr_epilogue(STEP_TIMER_NUM); }

ifdef CPU_32_BIT

define STEP_MULTIPLY(A,B) MultiU32X24toH32(A, B)

else

define STEP_MULTIPLY(A,B) MultiU24X32toH16(A, B)

endif

void Stepper::isr() {

ifndef AVR

// Disable interrupts, to avoid ISR preemption while we reprogram the period
// (AVR enters the ISR with global interrupts disabled, so no need to do it here)
DISABLE_ISRS();

endif

// Program timer compare for the maximum period, so it does NOT // flag an interrupt while this ISR is running - So changes from small // periods to big periods are respected and the timer does not reset to 0 HAL_timer_set_compare(STEP_TIMER_NUM, HAL_TIMER_TYPE_MAX);

// Count of ticks for the next ISR hal_timer_t next_isr_ticks = 0;

// Limit the amount of iterations uint8_t max_loops = 10;

// We need this variable here to be able to use it in the following loop hal_timer_t min_ticks; do { // Enable ISRs to reduce USART processing latency ENABLE_ISRS();

// Run main stepping pulse phase ISR if we have to
if (!nextMainISR) Stepper::stepper_pulse_phase_isr();

#if ENABLED(LIN_ADVANCE)
  // Run linear advance stepper ISR if we have to
  if (!nextAdvanceISR) nextAdvanceISR = Stepper::advance_isr();
#endif

// ^== Time critical. NOTHING besides pulse generation should be above here!!!

// Run main stepping block processing ISR if we have to
if (!nextMainISR) nextMainISR = Stepper::stepper_block_phase_isr();

uint32_t interval =
  #if ENABLED(LIN_ADVANCE)
    MIN(nextAdvanceISR, nextMainISR)  // Nearest time interval
  #else
    nextMainISR                       // Remaining stepper ISR time
  #endif
;

// Limit the value to the maximum possible value of the timer
NOMORE(interval, HAL_TIMER_TYPE_MAX);

// Compute the time remaining for the main isr
nextMainISR -= interval;

#if ENABLED(LIN_ADVANCE)
  // Compute the time remaining for the advance isr
  if (nextAdvanceISR != LA_ADV_NEVER) nextAdvanceISR -= interval;
#endif

/**
 * This needs to avoid a race-condition caused by interleaving
 * of interrupts required by both the LA and Stepper algorithms.
 *
 * Assume the following tick times for stepper pulses:
 *   Stepper ISR (S):  1 1000 2000 3000 4000
 *   Linear Adv. (E): 10 1010 2010 3010 4010
 *
 * The current algorithm tries to interleave them, giving:
 *  1:S 10:E 1000:S 1010:E 2000:S 2010:E 3000:S 3010:E 4000:S 4010:E
 *
 * Ideal timing would yield these delta periods:
 *  1:S  9:E  990:S   10:E  990:S   10:E  990:S   10:E  990:S   10:E
 *
 * But, since each event must fire an ISR with a minimum duration, the
 * minimum delta might be 900, so deltas under 900 get rounded up:
 *  900:S d900:E d990:S d900:E d990:S d900:E d990:S d900:E d990:S d900:E
 *
 * It works, but divides the speed of all motors by half, leading to a sudden
 * reduction to 1/2 speed! Such jumps in speed lead to lost steps (not even
 * accounting for double/quad stepping, which makes it even worse).
 */

// Compute the tick count for the next ISR
next_isr_ticks += interval;

/**
 * The following section must be done with global interrupts disabled.
 * We want nothing to interrupt it, as that could mess the calculations
 * we do for the next value to program in the period register of the
 * stepper timer and lead to skipped ISRs (if the value we happen to program
 * is less than the current count due to something preempting between the
 * read and the write of the new period value).
 */
DISABLE_ISRS();

/**
 * Get the current tick value + margin
 * Assuming at least 6µs between calls to this ISR...
 * On AVR the ISR epilogue+prologue is estimated at 100 instructions - Give 8µs as margin
 * On ARM the ISR epilogue+prologue is estimated at 20 instructions - Give 1µs as margin
 */
min_ticks = HAL_timer_get_count(STEP_TIMER_NUM) + hal_timer_t(
  #ifdef __AVR__
    8
  #else
    1
  #endif
  * (STEPPER_TIMER_TICKS_PER_US)
);

/**
 * NB: If for some reason the stepper monopolizes the MPU, eventually the
 * timer will wrap around (and so will 'next_isr_ticks'). So, limit the
 * loop to 10 iterations. Beyond that, there's no way to ensure correct pulse
 * timing, since the MCU isn't fast enough.
 */
if (!--max_loops) next_isr_ticks = min_ticks;

// Advance pulses if not enough time to wait for the next ISR

} while (next_isr_ticks < min_ticks);

// Now 'next_isr_ticks' contains the period to the next Stepper ISR - And we are // sure that the time has not arrived yet - Warrantied by the scheduler

// Set the next ISR to fire at the proper time HAL_timer_set_compare(STEP_TIMER_NUM, hal_timer_t(next_isr_ticks));

// Don't forget to finally reenable interrupts ENABLE_ISRS(); }

/**

// This is the last half of the stepper interrupt: This one processes and // properly schedules blocks from the planner. This is executed after creating // the step pulses, so it is not time critical, as pulses are already done.

uint32_t Stepper::stepper_block_phase_isr() {

// If no queued movements, just wait 1ms for the next move uint32_t interval = (STEPPER_TIMER_RATE / 1000);

// If there is a current block if (current_block) {

// If current block is finished, reset pointer
if (step_events_completed >= step_event_count) {
  #if FILAMENT_RUNOUT_DISTANCE_MM > 0
    runout.block_completed(current_block);
  #endif
  axis_did_move = 0;
  current_block = NULL;
  planner.discard_current_block();
}
else {
  // Step events not completed yet...

  // Are we in acceleration phase ?
  if (step_events_completed <= accelerate_until) { // Calculate new timer value

    #if ENABLED(S_CURVE_ACCELERATION)
      // Get the next speed to use (Jerk limited!)
      uint32_t acc_step_rate =
        acceleration_time < current_block->acceleration_time
          ? _eval_bezier_curve(acceleration_time)
          : current_block->cruise_rate;
    #else
      acc_step_rate = STEP_MULTIPLY(acceleration_time, current_block->acceleration_rate) + current_block->initial_rate;
      NOMORE(acc_step_rate, current_block->nominal_rate);
    #endif

    // acc_step_rate is in steps/second

    // step_rate to timer interval and steps per stepper isr
    interval = calc_timer_interval(acc_step_rate, oversampling_factor, &steps_per_isr);
    acceleration_time += interval;

    #if ENABLED(LIN_ADVANCE)
      if (LA_use_advance_lead) {
        // Fire ISR if final adv_rate is reached
        if (LA_steps && LA_isr_rate != current_block->advance_speed) nextAdvanceISR = 0;
      }
      else if (LA_steps) nextAdvanceISR = 0;
    #endif // LIN_ADVANCE
  }
  // Are we in Deceleration phase ?
  else if (step_events_completed > decelerate_after) {
    uint32_t step_rate;

    #if ENABLED(S_CURVE_ACCELERATION)
      // If this is the 1st time we process the 2nd half of the trapezoid...
      if (!bezier_2nd_half) {
        // Initialize the Bézier speed curve
        _calc_bezier_curve_coeffs(current_block->cruise_rate, current_block->final_rate, current_block->deceleration_time_inverse);
        bezier_2nd_half = true;
        // The first point starts at cruise rate. Just save evaluation of the Bézier curve
        step_rate = current_block->cruise_rate;
      }
      else {
        // Calculate the next speed to use
        step_rate = deceleration_time < current_block->deceleration_time
          ? _eval_bezier_curve(deceleration_time)
          : current_block->final_rate;
      }
    #else

      // Using the old trapezoidal control
      step_rate = STEP_MULTIPLY(deceleration_time, current_block->acceleration_rate);
      if (step_rate < acc_step_rate) { // Still decelerating?
        step_rate = acc_step_rate - step_rate;
        NOLESS(step_rate, current_block->final_rate);
      }
      else
        step_rate = current_block->final_rate;
    #endif

    // step_rate is in steps/second

    // step_rate to timer interval and steps per stepper isr
    interval = calc_timer_interval(step_rate, oversampling_factor, &steps_per_isr);
    deceleration_time += interval;

    #if ENABLED(LIN_ADVANCE)
      if (LA_use_advance_lead) {
        // Wake up eISR on first deceleration loop and fire ISR if final adv_rate is reached
        if (step_events_completed <= decelerate_after + steps_per_isr || (LA_steps && LA_isr_rate != current_block->advance_speed)) {
          nextAdvanceISR = 0;
          LA_isr_rate = current_block->advance_speed;
        }
      }
      else if (LA_steps) nextAdvanceISR = 0;
    #endif // LIN_ADVANCE
  }
  // We must be in cruise phase otherwise
  else {

    #if ENABLED(LIN_ADVANCE)
      // If there are any esteps, fire the next advance_isr "now"
      if (LA_steps && LA_isr_rate != current_block->advance_speed) nextAdvanceISR = 0;
    #endif

    // Calculate the ticks_nominal for this nominal speed, if not done yet
    if (ticks_nominal < 0) {
      // step_rate to timer interval and loops for the nominal speed
      ticks_nominal = calc_timer_interval(current_block->nominal_rate, oversampling_factor, &steps_per_isr);
    }

    // The timer interval is just the nominal value for the nominal speed
    interval = ticks_nominal;
  }
}

}

// If there is no current block at this point, attempt to pop one from the buffer // and prepare its movement if (!current_block) {

// Anything in the buffer?
if ((current_block = planner.get_current_block())) {

  // Sync block? Sync the stepper counts and return
  while (TEST(current_block->flag, BLOCK_BIT_SYNC_POSITION)) {
    _set_position(
      current_block->position[A_AXIS], current_block->position[B_AXIS],
      current_block->position[C_AXIS],
      #if NON_E_AXES > 3
           current_block->position[I_AXIS],
        #if NON_E_AXES > 4
          current_block->position[J_AXIS],
          #if NON_E_AXES > 5
            current_block->position[K_AXIS],
          #endif
        #endif
      #endif
      current_block->position[E_AXIS]
    );
    planner.discard_current_block();

    // Try to get a new block
    if (!(current_block = planner.get_current_block()))
      return interval; // No more queued movements!
  }

  // Flag all moving axes for proper endstop handling

  #if IS_CORE
    // Define conditions for checking endstops
    #define S_(N) current_block->steps[CORE_AXIS_##N]
    #define D_(N) TEST(current_block->direction_bits, CORE_AXIS_##N)
  #endif

  #if CORE_IS_XY || CORE_IS_XZ
    /**
     * Head direction in -X axis for CoreXY and CoreXZ bots.
     *
     * If steps differ, both axes are moving.
     * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z, handled below)
     * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X)
     */
    #if ENABLED(COREXY) || ENABLED(COREXZ)
      #define X_CMP ==
    #else
      #define X_CMP !=
    #endif
    #define X_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) X_CMP D_(2)) )
  #else
    #define X_MOVE_TEST !!current_block->steps[A_AXIS]
  #endif

  #if CORE_IS_XY || CORE_IS_YZ
    /**
     * Head direction in -Y axis for CoreXY / CoreYZ bots.
     *
     * If steps differ, both axes are moving
     * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X or Y)
     * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z)
     */
    #if ENABLED(COREYX) || ENABLED(COREYZ)
      #define Y_CMP ==
    #else
      #define Y_CMP !=
    #endif
    #define Y_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Y_CMP D_(2)) )
  #else
    #define Y_MOVE_TEST !!current_block->steps[B_AXIS]
  #endif

  #if CORE_IS_XZ || CORE_IS_YZ
    /**
     * Head direction in -Z axis for CoreXZ or CoreYZ bots.
     *
     * If steps differ, both axes are moving
     * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X or Y, already handled above)
     * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Z)
     */
    #if ENABLED(COREZX) || ENABLED(COREZY)
      #define Z_CMP ==
    #else
      #define Z_CMP !=
    #endif
    #define Z_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) Z_CMP D_(2)) )
  #else
    #define Z_MOVE_TEST !!current_block->steps[C_AXIS]
  #endif

  #if NON_E_AXES > 3
    #if CORE_IS_XY || CORE_IS_YZ
      /**
       * Head direction in -Y axis for CoreXY / CoreYZ bots.
       *
       * If steps differ, both axes are moving
       * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X or Y)
       * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z)
       */
      #if ENABLED(COREYX) || ENABLED(COREYZ)
        #define I_CMP ==
      #else
        #define I_CMP !=
      #endif
      #define I_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) I_CMP D_(2)) )
    #else
      #define I_MOVE_TEST !!current_block->steps[I_AXIS]
    #endif
    #if NON_E_AXES > 4
      #if CORE_IS_XY || CORE_IS_YZ
        /**
         * Head direction in -Y axis for CoreXY / CoreYZ bots.
         *
         * If steps differ, both axes are moving
         * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X or Y)
         * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z)
         */
        #if ENABLED(COREYX) || ENABLED(COREYZ)
          #define J_CMP ==
        #else
          #define J_CMP !=
        #endif
        #define J_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) J_CMP D_(2)) )
      #else
        #define J_MOVE_TEST !!current_block->steps[J_AXIS]
      #endif
      #if NON_E_AXES > 5
        #if CORE_IS_XY || CORE_IS_YZ
          /**
           * Head direction in -Y axis for CoreXY / CoreYZ bots.
           *
           * If steps differ, both axes are moving
           * If DeltaA ==  DeltaB, the movement is only in the 1st axis (X or Y)
           * If DeltaA == -DeltaB, the movement is only in the 2nd axis (Y or Z)
           */
          #if ENABLED(COREYX) || ENABLED(COREYZ)
            #define K_CMP ==
          #else
            #define K_CMP !=
          #endif
          #define K_MOVE_TEST ( S_(1) != S_(2) || (S_(1) > 0 && D_(1) K_CMP D_(2)) )
        #else
          #define K_MOVE_TEST !!current_block->steps[K_AXIS]
        #endif
      #endif // NON_E_AXES > 5
    #endif // NON_E_AXES > 4
  #endif // NON_E_AXES > 3

  uint8_t axis_bits = 0;
  if (X_MOVE_TEST) SBI(axis_bits, A_AXIS);
  if (Y_MOVE_TEST) SBI(axis_bits, B_AXIS);
  if (Z_MOVE_TEST) SBI(axis_bits, C_AXIS);
  #if NON_E_AXES > 3
    if (I_MOVE_TEST) SBI(axis_bits, I_AXIS);
    #if NON_E_AXES > 4
      if (J_MOVE_TEST) SBI(axis_bits, J_AXIS);
      #if NON_E_AXES > 5
        if (K_MOVE_TEST) SBI(axis_bits, K_AXIS);
      #endif
    #endif
  #endif
  //if (!!current_block->steps[E_AXIS]) SBI(axis_bits, E_AXIS);
  //if (!!current_block->steps[A_AXIS]) SBI(axis_bits, X_HEAD);
  //if (!!current_block->steps[B_AXIS]) SBI(axis_bits, Y_HEAD);
  //if (!!current_block->steps[C_AXIS]) SBI(axis_bits, Z_HEAD);
  axis_did_move = axis_bits;

  // No acceleration / deceleration time elapsed so far
  acceleration_time = deceleration_time = 0;

  uint8_t oversampling = 0;                         // Assume we won't use it

  #if ENABLED(ADAPTIVE_STEP_SMOOTHING)
    // At this point, we must decide if we can use Stepper movement axis smoothing.
    uint32_t max_rate = current_block->nominal_rate;  // Get the maximum rate (maximum event speed)
    while (max_rate < MIN_STEP_ISR_FREQUENCY) {
      max_rate <<= 1;
      if (max_rate >= MAX_STEP_ISR_FREQUENCY_1X) break;
      ++oversampling;
    }
    oversampling_factor = oversampling;
  #endif

  // Based on the oversampling factor, do the calculations
  step_event_count = current_block->step_event_count << oversampling;

  // Initialize Bresenham delta errors to 1/2
  delta_error[X_AXIS] = delta_error[Y_AXIS] = delta_error[Z_AXIS] = delta_error[E_AXIS]
    #if NON_E_AXES > 3
      = delta_error[I_AXIS]
      #if NON_E_AXES > 4
        = delta_error[J_AXIS]
        #if NON_E_AXES > 5
          = delta_error[K_AXIS]
        #endif
      #endif
    #endif
    = -int32_t(step_event_count);

  // Calculate Bresenham dividends
  advance_dividend[X_AXIS] = current_block->steps[X_AXIS] << 1;
  advance_dividend[Y_AXIS] = current_block->steps[Y_AXIS] << 1;
  advance_dividend[Z_AXIS] = current_block->steps[Z_AXIS] << 1;
  #if NON_E_AXES > 3
    advance_dividend[I_AXIS] = current_block->steps[I_AXIS] << 1;
    #if NON_E_AXES > 4
      advance_dividend[J_AXIS] = current_block->steps[J_AXIS] << 1;
      #if NON_E_AXES > 5
       advance_dividend[K_AXIS] = current_block->steps[K_AXIS] << 1;
      #endif
    #endif
  #endif
  advance_dividend[E_AXIS] = current_block->steps[E_AXIS] << 1;

  // Calculate Bresenham divisor
  advance_divisor = step_event_count << 1;

  // No step events completed so far
  step_events_completed = 0;

  // Compute the acceleration and deceleration points
  accelerate_until = current_block->accelerate_until << oversampling;
  decelerate_after = current_block->decelerate_after << oversampling;

  #if ENABLED(MIXING_EXTRUDER)
    MIXER_STEPPER_SETUP();
  #endif

  #if EXTRUDERS > 1
    stepper_extruder = current_block->extruder;
  #endif

  // Initialize the trapezoid generator from the current block.
  #if ENABLED(LIN_ADVANCE)
    #if DISABLED(MIXING_EXTRUDER) && E_STEPPERS > 1
      // If the now active extruder wasn't in use during the last move, its pressure is most likely gone.
      if (stepper_extruder != last_moved_extruder) LA_current_adv_steps = 0;
    #endif

    if ((LA_use_advance_lead = current_block->use_advance_lead)) {
      LA_final_adv_steps = current_block->final_adv_steps;
      LA_max_adv_steps = current_block->max_adv_steps;
      //Start the ISR
      nextAdvanceISR = 0;
      LA_isr_rate = current_block->advance_speed;
    }
    else LA_isr_rate = LA_ADV_NEVER;
  #endif

  if (
    #if HAS_DRIVER(L6470)
      true  // Always set direction for L6470 (This also enables the chips)
    #else
      current_block->direction_bits != last_direction_bits
      #if DISABLED(MIXING_EXTRUDER)
        || stepper_extruder != last_moved_extruder
      #endif
    #endif
  ) {
    last_direction_bits = current_block->direction_bits;
    #if EXTRUDERS > 1
      last_moved_extruder = stepper_extruder;
    #endif
    set_directions();
  }

  // At this point, we must ensure the movement about to execute isn't
  // trying to force the head against a limit switch. If using interrupt-
  // driven change detection, and already against a limit then no call to
  // the endstop_triggered method will be done and the movement will be
  // done against the endstop. So, check the limits here: If the movement
  // is against the limits, the block will be marked as to be killed, and
  // on the next call to this ISR, will be discarded.
  endstops.update();

  #if ENABLED(Z_LATE_ENABLE)
    // If delayed Z enable, enable it now. This option will severely interfere with
    // timing between pulses when chaining motion between blocks, and it could lead
    // to lost steps in both X and Y axis, so avoid using it unless strictly necessary!!
    if (current_block->steps[Z_AXIS]) enable_Z();
  #endif

  // Mark the time_nominal as not calculated yet
  ticks_nominal = -1;

  #if DISABLED(S_CURVE_ACCELERATION)
    // Set as deceleration point the initial rate of the block  Đặt làm điểm giảm tốc tốc độ ban đầu của khối
    acc_step_rate = current_block->initial_rate;
  #endif

  #if ENABLED(S_CURVE_ACCELERATION)
    // Initialize the Bézier speed curve
    _calc_bezier_curve_coeffs(current_block->initial_rate, current_block->cruise_rate, current_block->acceleration_time_inverse);
    // We haven't started the 2nd half of the trapezoid
    bezier_2nd_half = false;
  #endif

  // Calculate the initial timer interval     Tính khoảng thời gian hẹn giờ ban đầu
  interval = calc_timer_interval(current_block->initial_rate, oversampling_factor, &steps_per_isr);
}

}

// Return the interval to wait Trả lại khoảng thời gian chờ đợi return interval; }

if ENABLED(LIN_ADVANCE)

// Timer interrupt for E. LA_steps is set in the main routine uint32_t Stepper::advance_isr() { uint32_t interval;

if (LA_use_advance_lead) {
  if (step_events_completed > decelerate_after && LA_current_adv_steps > LA_final_adv_steps) {
    LA_steps--;
    LA_current_adv_steps--;
    interval = LA_isr_rate;
  }
  else if (step_events_completed < decelerate_after && LA_current_adv_steps < LA_max_adv_steps) {
         //step_events_completed <= (uint32_t)accelerate_until) {
    LA_steps++;
    LA_current_adv_steps++;
    interval = LA_isr_rate;
  }
  else
    interval = LA_isr_rate = LA_ADV_NEVER;
}
else
  interval = LA_ADV_NEVER;

  #if ENABLED(MIXING_EXTRUDER)
    // We don't know which steppers will be stepped because LA loop follows,
    // with potentially multiple steps. Set all.
    if (LA_steps >= 0)
      MIXER_STEPPER_LOOP(j) NORM_E_DIR(j);
    else
      MIXER_STEPPER_LOOP(j) REV_E_DIR(j);
  #else
    if (LA_steps >= 0)
      NORM_E_DIR(stepper_extruder);
    else
      REV_E_DIR(stepper_extruder);
  #endif

// Get the timer count and estimate the end of the pulse
hal_timer_t pulse_end = HAL_timer_get_count(PULSE_TIMER_NUM) + hal_timer_t(MIN_PULSE_TICKS);

const hal_timer_t added_step_ticks = hal_timer_t(ADDED_STEP_TICKS);

// Step E stepper if we have steps
while (LA_steps) {

  // Set the STEP pulse ON
  #if ENABLED(MIXING_EXTRUDER)
    E_STEP_WRITE(mixer.get_next_stepper(), !INVERT_E_STEP_PIN);
  #else
    E_STEP_WRITE(stepper_extruder, !INVERT_E_STEP_PIN);
  #endif

  // Enforce a minimum duration for STEP pulse ON
  #if MINIMUM_STEPPER_PULSE
    // Just wait for the requested pulse duration
    while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
  #endif

  // Add the delay needed to ensure the maximum driver rate is enforced
  if (signed(added_step_ticks) > 0) pulse_end += hal_timer_t(added_step_ticks);

  LA_steps < 0 ? ++LA_steps : --LA_steps;

  // Set the STEP pulse OFF
  #if ENABLED(MIXING_EXTRUDER)
    E_STEP_WRITE(mixer.get_stepper(), INVERT_E_STEP_PIN);
  #else
    E_STEP_WRITE(stepper_extruder, INVERT_E_STEP_PIN);
  #endif

  // For minimum pulse time wait before looping
  // Just wait for the requested pulse duration
  if (LA_steps) {
    while (HAL_timer_get_count(PULSE_TIMER_NUM) < pulse_end) { /* nada */ }
    #if MINIMUM_STEPPER_PULSE
      // Add to the value, the time that the pulse must be active (to be used on the next loop)
      pulse_end += hal_timer_t(MIN_PULSE_TICKS);
    #endif
  }
} // LA_steps

return interval;

}

endif // LIN_ADVANCE

// Check if the given block is busy or not - Must not be called from ISR contexts // The current_block could change in the middle of the read by an Stepper ISR, so // we must explicitly prevent that! bool Stepper::is_block_busy(const block_t* const block) {

ifdef AVR

// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");

// Keep reading until 2 consecutive reads return the same value,
// meaning there was no update in-between caused by an interrupt.
// This works because stepper ISRs happen at a slower rate than
// successive reads of a variable, so 2 consecutive reads with
// the same value means no interrupt updated it.
block_t* vold, *vnew = current_block;
sw_barrier();
do {
  vold = vnew;
  vnew = current_block;
  sw_barrier();
} while (vold != vnew);

else

block_t *vnew = current_block;

endif

// Return if the block is busy or not return block == vnew; }

void Stepper::init() {

// Init Digipot Motor Current

if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM

digipot_init();

endif

if MB(ALLIGATOR)

const float motor_current[] = MOTOR_CURRENT;
unsigned int digipot_motor = 0;
for (uint8_t i = 0; i < 3 + EXTRUDERS; i++) {
  digipot_motor = 255 * (motor_current[i] / 2.5);
  dac084s085::setValue(i, digipot_motor);
}

endif//MB(ALLIGATOR)

// Init Microstepping Pins

if HAS_MICROSTEPS

microstep_init();

endif

// Init Dir Pins

if HAS_X_DIR

X_DIR_INIT;

endif

if HAS_X2_DIR

X2_DIR_INIT;

endif

if HAS_Y_DIR

Y_DIR_INIT;
#if ENABLED(Y_DUAL_STEPPER_DRIVERS) && HAS_Y2_DIR
  Y2_DIR_INIT;
#endif

endif

if HAS_Z_DIR

Z_DIR_INIT;
#if Z_MULTI_STEPPER_DRIVERS && HAS_Z2_DIR
  Z2_DIR_INIT;
#endif
#if ENABLED(Z_TRIPLE_STEPPER_DRIVERS) && HAS_Z3_DIR
  Z3_DIR_INIT;
#endif

endif

if HAS_I_DIR

I_DIR_INIT;

endif

if HAS_J_DIR

J_DIR_INIT;

endif

if HAS_K_DIR

K_DIR_INIT;

endif

if HAS_E0_DIR

E0_DIR_INIT;

endif

if HAS_E1_DIR

E1_DIR_INIT;

endif

if HAS_E2_DIR

E2_DIR_INIT;

endif

if HAS_E3_DIR

E3_DIR_INIT;

endif

if HAS_E4_DIR

E4_DIR_INIT;

endif

if HAS_E5_DIR

E5_DIR_INIT;

endif

// Init Enable Pins - steppers default to disabled.

if HAS_X_ENABLE

X_ENABLE_INIT;
if (!X_ENABLE_ON) X_ENABLE_WRITE(HIGH);
#if (ENABLED(DUAL_X_CARRIAGE) || ENABLED(X_DUAL_STEPPER_DRIVERS)) && HAS_X2_ENABLE
  X2_ENABLE_INIT;
  if (!X_ENABLE_ON) X2_ENABLE_WRITE(HIGH);
#endif

endif

if HAS_Y_ENABLE

Y_ENABLE_INIT;
if (!Y_ENABLE_ON) Y_ENABLE_WRITE(HIGH);
#if ENABLED(Y_DUAL_STEPPER_DRIVERS) && HAS_Y2_ENABLE
  Y2_ENABLE_INIT;
  if (!Y_ENABLE_ON) Y2_ENABLE_WRITE(HIGH);
#endif

endif

if HAS_Z_ENABLE

Z_ENABLE_INIT;
if (!Z_ENABLE_ON) Z_ENABLE_WRITE(HIGH);
#if Z_MULTI_STEPPER_DRIVERS && HAS_Z2_ENABLE
  Z2_ENABLE_INIT;
  if (!Z_ENABLE_ON) Z2_ENABLE_WRITE(HIGH);
#endif
#if ENABLED(Z_TRIPLE_STEPPER_DRIVERS) && HAS_Z3_ENABLE
  Z3_ENABLE_INIT;
  if (!Z_ENABLE_ON) Z3_ENABLE_WRITE(HIGH);
#endif

endif

if HAS_I_ENABLE

I_ENABLE_INIT;
if (!I_ENABLE_ON) I_ENABLE_WRITE(HIGH);

endif

if HAS_J_ENABLE

J_ENABLE_INIT;
if (!J_ENABLE_ON) J_ENABLE_WRITE(HIGH);

endif

if HAS_K_ENABLE

K_ENABLE_INIT;
if (!K_ENABLE_ON) K_ENABLE_WRITE(HIGH);

endif

if HAS_E0_ENABLE

E0_ENABLE_INIT;
if (!E_ENABLE_ON) E0_ENABLE_WRITE(HIGH);

endif

if HAS_E1_ENABLE

E1_ENABLE_INIT;
if (!E_ENABLE_ON) E1_ENABLE_WRITE(HIGH);

endif

if HAS_E2_ENABLE

E2_ENABLE_INIT;
if (!E_ENABLE_ON) E2_ENABLE_WRITE(HIGH);

endif

if HAS_E3_ENABLE

E3_ENABLE_INIT;
if (!E_ENABLE_ON) E3_ENABLE_WRITE(HIGH);

endif

if HAS_E4_ENABLE

E4_ENABLE_INIT;
if (!E_ENABLE_ON) E4_ENABLE_WRITE(HIGH);

endif

if HAS_E5_ENABLE

E5_ENABLE_INIT;
if (!E_ENABLE_ON) E5_ENABLE_WRITE(HIGH);

endif

define _STEP_INIT(AXIS) AXIS ##_STEP_INIT

define _WRITE_STEP(AXIS, HIGHLOW) AXIS ##_STEP_WRITE(HIGHLOW)

define DISABLE(AXIS) disable## AXIS()

define AXIS_INIT(AXIS, PIN) \

_STEP_INIT(AXIS); \
_WRITE_STEP(AXIS, _INVERT_STEP_PIN(PIN)); \
_DISABLE(AXIS)

define E_AXIS_INIT(NUM) AXIS_INIT(E## NUM, E)

// Init Step Pins

if HAS_X_STEP

#if ENABLED(X_DUAL_STEPPER_DRIVERS) || ENABLED(DUAL_X_CARRIAGE)
  X2_STEP_INIT;
  X2_STEP_WRITE(INVERT_X_STEP_PIN);
#endif
AXIS_INIT(X, X);

endif

if HAS_Y_STEP

#if ENABLED(Y_DUAL_STEPPER_DRIVERS)
  Y2_STEP_INIT;
  Y2_STEP_WRITE(INVERT_Y_STEP_PIN);
#endif
AXIS_INIT(Y, Y);

endif

if HAS_Z_STEP

#if Z_MULTI_STEPPER_DRIVERS
  Z2_STEP_INIT;
  Z2_STEP_WRITE(INVERT_Z_STEP_PIN);
#endif
#if ENABLED(Z_TRIPLE_STEPPER_DRIVERS)
  Z3_STEP_INIT;
  Z3_STEP_WRITE(INVERT_Z_STEP_PIN);
#endif
AXIS_INIT(Z, Z);

endif

if HAS_I_STEP

AXIS_INIT(I, I);

endif

if HAS_J_STEP

AXIS_INIT(J, J);

endif

if HAS_K_STEP

AXIS_INIT(K, K);

endif

if E_STEPPERS > 0 && HAS_E0_STEP

E_AXIS_INIT(0);

endif

if E_STEPPERS > 1 && HAS_E1_STEP

E_AXIS_INIT(1);

endif

if E_STEPPERS > 2 && HAS_E2_STEP

E_AXIS_INIT(2);

endif

if E_STEPPERS > 3 && HAS_E3_STEP

E_AXIS_INIT(3);

endif

if E_STEPPERS > 4 && HAS_E4_STEP

E_AXIS_INIT(4);

endif

if E_STEPPERS > 5 && HAS_E5_STEP

E_AXIS_INIT(5);

endif

if DISABLED(I2S_STEPPER_STREAM)

HAL_timer_start(STEP_TIMER_NUM, 122); // Init Stepper ISR to 122 Hz for quick starting
ENABLE_STEPPER_DRIVER_INTERRUPT();
sei();

endif

// Init direction bits for first moves Ban đầu hướng bit cho di chuyển đầu tiên last_direction_bits = 0 | (INVERT_X_DIR ? _BV(X_AXIS) : 0) | (INVERT_Y_DIR ? _BV(Y_AXIS) : 0) | (INVERT_Z_DIR ? _BV(Z_AXIS) : 0)

if NON_E_AXES > 3

  | (INVERT_I_DIR ? _BV(I_AXIS) : 0)
  #if NON_E_AXES > 4
    | (INVERT_J_DIR ? _BV(J_AXIS) : 0)
    #if NON_E_AXES > 5
    | (INVERT_K_DIR ? _BV(K_AXIS) : 0)
    #endif
  #endif
#endif
;

set_directions(); }

/**

/**

// Signal endstops were triggered - This function can be called from // an ISR context (Temperature, Stepper or limits ISR), so we must // be very careful here. If the interrupt being preempted was the // Stepper ISR (this CAN happen with the endstop limits ISR) then // when the stepper ISR resumes, we must be very sure that the movement // is properly cancelled void Stepper::endstop_triggered(const AxisEnum axis) {

const bool was_enabled = STEPPER_ISR_ENABLED(); if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();

if IS_CORE

endstops_trigsteps[axis] = 0.5f * (
  axis == CORE_AXIS_2 ? CORESIGN(count_position[CORE_AXIS_1] - count_position[CORE_AXIS_2])
                      : count_position[CORE_AXIS_1] + count_position[CORE_AXIS_2]
);

else // !COREXY && !COREXZ && !COREYZ

endstops_trigsteps[axis] = count_position[axis];

endif // !COREXY && !COREXZ && !COREYZ

// Discard the rest of the move if there is a current block quick_stop();

if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT(); }

int32_t Stepper::triggered_position(const AxisEnum axis) {

ifdef AVR

// Protect the access to the position. Only required for AVR, as
//  any 32bit CPU offers atomic access to 32bit variables
const bool was_enabled = STEPPER_ISR_ENABLED();
if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();

endif

const int32_t v = endstops_trigsteps[axis];

ifdef AVR

// Reenable Stepper ISR
if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();

endif

return v; }

void Stepper::report_positions() {

// Protect the access to the position. const bool was_enabled = STEPPER_ISR_ENABLED(); if (was_enabled) DISABLE_STEPPER_DRIVER_INTERRUPT();

const int32_t xpos = count_position[X_AXIS] , ypos = count_position[Y_AXIS] , zpos = count_position[Z_AXIS] ,

if NON_E_AXES > 3

               ipos = count_position[I_AXIS],
              #if NON_E_AXES > 4
              jpos = count_position[J_AXIS],
                #if NON_E_AXES > 5
                   kpos = count_position[K_AXIS];
                #endif
              #endif
            #endif

if (was_enabled) ENABLE_STEPPER_DRIVER_INTERRUPT();

if CORE_IS_XY || CORE_IS_XZ || ENABLED(DELTA) || IS_SCARA

SERIAL_ECHOPGM(MSG_COUNT_A);

else

SERIAL_ECHOPGM(MSG_COUNT_X);

endif

SERIAL_ECHO(xpos);

if CORE_IS_XY || CORE_IS_YZ || ENABLED(DELTA) || IS_SCARA

SERIAL_ECHOPGM(" B:");

else

SERIAL_ECHOPGM(" Y:");

endif

SERIAL_ECHO(ypos);

if CORE_IS_XZ || CORE_IS_YZ || ENABLED(DELTA)

SERIAL_ECHOPGM(" C:");

else

SERIAL_ECHOPGM(" Z:");

endif

SERIAL_ECHO(zpos);

if NON_E_AXES > 3

SERIAL_ECHOPGM(" I:");
SERIAL_ECHO(ipos);
#if NON_E_AXES > 4
  SERIAL_ECHOPGM(" J:");
  SERIAL_ECHO(jpos);
  #if NON_E_AXES > 5
    SERIAL_ECHOPGM(" K:");
    SERIAL_ECHO(kpos);
  #endif
#endif

endif

SERIAL_EOL(); }

if ENABLED(BABYSTEPPING)

if MINIMUM_STEPPER_PULSE

#define STEP_PULSE_CYCLES ((MINIMUM_STEPPER_PULSE) * CYCLES_PER_MICROSECOND)

else

#define STEP_PULSE_CYCLES 0

endif

if ENABLED(DELTA)

#define CYCLES_EATEN_BABYSTEP (2 * 15)

else

#define CYCLES_EATEN_BABYSTEP 0

endif

define EXTRA_CYCLES_BABYSTEP (STEP_PULSE_CYCLES - (CYCLES_EATEN_BABYSTEP))

define ENABLE(AXIS) enable## AXIS()

define _READ_DIR(AXIS) AXIS ##_DIR_READ

define _INVERTDIR(AXIS) INVERT## AXIS ##_DIR

define _APPLY_DIR(AXIS, INVERT) AXIS ##_APPLY_DIR(INVERT, true)

if EXTRA_CYCLES_BABYSTEP > 20

#define _SAVE_START const hal_timer_t pulse_start = HAL_timer_get_count(PULSE_TIMER_NUM)
#define _PULSE_WAIT while (EXTRA_CYCLES_BABYSTEP > (uint32_t)(HAL_timer_get_count(PULSE_TIMER_NUM) - pulse_start) * (PULSE_TIMER_PRESCALE)) { /* nada */ }

else

#define _SAVE_START NOOP
#if EXTRA_CYCLES_BABYSTEP > 0
  #define _PULSE_WAIT DELAY_NS(EXTRA_CYCLES_BABYSTEP * NANOSECONDS_PER_CYCLE)
#elif STEP_PULSE_CYCLES > 0
  #define _PULSE_WAIT NOOP
#elif ENABLED(DELTA)
  #define _PULSE_WAIT DELAY_US(2);
#else
  #define _PULSE_WAIT DELAY_US(4);
#endif

endif

define BABYSTEP_AXIS(AXIS, INVERT, DIR) { \

  const uint8_t old_dir = _READ_DIR(AXIS);          \
  _ENABLE(AXIS);                                    \
  _APPLY_DIR(AXIS, _INVERT_DIR(AXIS)^DIR^INVERT);   \
  DELAY_NS(MINIMUM_STEPPER_DIR_DELAY);              \
  _SAVE_START;                                      \
  _APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS), true); \
  _PULSE_WAIT;                                      \
  _APPLY_STEP(AXIS)(_INVERT_STEP_PIN(AXIS), true);  \
  _APPLY_DIR(AXIS, old_dir);                        \
}

// MUST ONLY BE CALLED BY AN ISR, // No other ISR should ever interrupt this! void Stepper::babystep(const AxisEnum axis, const bool direction) { cli();

switch (axis) {

  #if ENABLED(BABYSTEP_XY)

    case X_AXIS:
      #if CORE_IS_XY
        BABYSTEP_AXIS(X, false, direction);
        BABYSTEP_AXIS(Y, false, direction);
      #elif CORE_IS_XZ
        BABYSTEP_AXIS(X, false, direction);
        BABYSTEP_AXIS(Z, false, direction);
      #else
        BABYSTEP_AXIS(X, false, direction);
      #endif
      break;

    case Y_AXIS:
      #if CORE_IS_XY
        BABYSTEP_AXIS(X, false, direction);
        BABYSTEP_AXIS(Y, false, direction^(CORESIGN(1)<0));
      #elif CORE_IS_YZ
        BABYSTEP_AXIS(Y, false, direction);
        BABYSTEP_AXIS(Z, false, direction^(CORESIGN(1)<0));
      #else
        BABYSTEP_AXIS(Y, false, direction);
      #endif
      break;

  #endif

  case Z_AXIS: {

    #if CORE_IS_XZ
      BABYSTEP_AXIS(X, BABYSTEP_INVERT_Z, direction);
      BABYSTEP_AXIS(Z, BABYSTEP_INVERT_Z, direction^(CORESIGN(1)<0));

    #elif CORE_IS_YZ
      BABYSTEP_AXIS(Y, BABYSTEP_INVERT_Z, direction);
      BABYSTEP_AXIS(Z, BABYSTEP_INVERT_Z, direction^(CORESIGN(1)<0));

    #elif DISABLED(DELTA)
      BABYSTEP_AXIS(Z, BABYSTEP_INVERT_Z, direction);

    #else // DELTA

      const bool z_direction = direction ^ BABYSTEP_INVERT_Z;

      enable_X();
      enable_Y();
      enable_Z();
      #if NON_E_AXES > 3
        enable_I();
        #if NON_E_AXES > 4
          enable_J();
          #if NON_E_AXES > 5
            enable_K();
          #endif
        #endif
      #endif
      const uint8_t old_x_dir_pin = X_DIR_READ,
                    old_y_dir_pin = Y_DIR_READ,
                    old_z_dir_pin = Z_DIR_READ;
      #if NON_E_AXES > 3
        const uint8_t old_i_dir_pin = I_DIR_READ;
        #if NON_E_AXES > 3
          const uint8_t old_j_dir_pin = J_DIR_READ;
          #if NON_E_AXES > 3
            const uint8_t old_k_dir_pin = K_DIR_READ;
          #endif
        #endif
      #endif
      X_DIR_WRITE(INVERT_X_DIR ^ z_direction);
      Y_DIR_WRITE(INVERT_Y_DIR ^ z_direction);
      Z_DIR_WRITE(INVERT_Z_DIR ^ z_direction);
      #if NON_E_AXES > 3
        I_DIR_WRITE(INVERT_I_DIR ^ z_direction);
        #if NON_E_AXES > 3
          J_DIR_WRITE(INVERT_J_DIR ^ z_direction);
          #if NON_E_AXES > 3
            K_DIR_WRITE(INVERT_K_DIR ^ z_direction);
          #endif
        #endif
      #endif
      #if MINIMUM_STEPPER_DIR_DELAY > 0
        DELAY_NS(MINIMUM_STEPPER_DIR_DELAY);
      #endif

      _SAVE_START;

      X_STEP_WRITE(!INVERT_X_STEP_PIN);
      Y_STEP_WRITE(!INVERT_Y_STEP_PIN);
      Z_STEP_WRITE(!INVERT_Z_STEP_PIN);
      #if NON_E_AXES > 3
        I_STEP_WRITE(!INVERT_I_STEP_PIN);
        #if NON_E_AXES > 4
          J_STEP_WRITE(!INVERT_J_STEP_PIN);
          #if NON_E_AXES > 5
            K_STEP_WRITE(!INVERT_K_STEP_PIN);
          #endif
        #endif
      #endif
      _PULSE_WAIT;

      X_STEP_WRITE(INVERT_X_STEP_PIN);
      Y_STEP_WRITE(INVERT_Y_STEP_PIN);
      Z_STEP_WRITE(INVERT_Z_STEP_PIN);
      #if NON_E_AXES > 3
        I_STEP_WRITE(INVERT_I_STEP_PIN);
        #if NON_E_AXES > 4
          J_STEP_WRITE(INVERT_J_STEP_PIN);
          #if NON_E_AXES > 5
            K_STEP_WRITE(INVERT_K_STEP_PIN);
          #endif
        #endif
      #endif

      // Restore direction bits
      X_DIR_WRITE(old_x_dir_pin);
      Y_DIR_WRITE(old_y_dir_pin);
      Z_DIR_WRITE(old_z_dir_pin);
      #if NON_E_AXES > 3
        I_DIR_WRITE(old_i_dir_pin);
        #if NON_E_AXES > 4
          J_DIR_WRITE(old_j_dir_pin);
          #if NON_E_AXES > 5
            K_DIR_WRITE(old_k_dir_pin);
          #endif
        #endif
      #endif
    #endif

  } break;

  #if NON_E_AXES > 3
    case I_AXIS:
      BABYSTEP_AXIS(I, false, direction);
      break;
    #if NON_E_AXES > 4
      case J_AXIS:
        BABYSTEP_AXIS(J, false, direction);
        break;
      #if NON_E_AXES > 5
        case K_AXIS:
          BABYSTEP_AXIS(K, false, direction);
          break;
      #endif // NON_E_AXES > 5
    #endif // NON_E_AXES > 4
  #endif // NON_E_AXES > 3

  default: break;
}
sei();

}

endif // BABYSTEPPING

/**

if HAS_DIGIPOTSS

// From Arduino DigitalPotControl example void Stepper::digitalPotWrite(const int16_t address, const int16_t value) { WRITE(DIGIPOTSS_PIN, LOW); // Take the SS pin low to select the chip SPI.transfer(address); // Send the address and value via SPI SPI.transfer(value); WRITE(DIGIPOTSS_PIN, HIGH); // Take the SS pin high to de-select the chip //delay(10); }

endif // HAS_DIGIPOTSS

if HAS_MOTOR_CURRENT_PWM

void Stepper::refresh_motor_power() { LOOP_L_N(i, COUNT(motor_current_setting)) { switch (i) {

if PIN_EXISTS(MOTOR_CURRENT_PWM_XY) || PIN_EXISTS(MOTOR_CURRENT_PWM_X) || PIN_EXISTS(MOTOR_CURRENT_PWM_Y)

      case 0:
    #endif
    #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
      case 1:
    #endif
    #if PIN_EXISTS(MOTOR_CURRENT_PWM_E) || PIN_EXISTS(MOTOR_CURRENT_PWM_E0) || PIN_EXISTS(MOTOR_CURRENT_PWM_E1)
      case 2:
    #endif
        digipot_current(i, motor_current_setting[i]);
    default: break;
  }
}

}

endif // HAS_MOTOR_CURRENT_PWM

if HAS_DIGIPOTSS || HAS_MOTOR_CURRENT_PWM

void Stepper::digipot_current(const uint8_t driver, const int16_t current) {

#if HAS_DIGIPOTSS

  const uint8_t digipot_ch[] = DIGIPOT_CHANNELS;
  digitalPotWrite(digipot_ch[driver], current);

#elif HAS_MOTOR_CURRENT_PWM

  if (WITHIN(driver, 0, COUNT(motor_current_setting) - 1))
    motor_current_setting[driver] = current; // update motor_current_setting

  #define _WRITE_CURRENT_PWM(P) analogWrite(MOTOR_CURRENT_PWM_## P ##_PIN, 255L * current / (MOTOR_CURRENT_PWM_RANGE))
  switch (driver) {
    case 0:
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
        _WRITE_CURRENT_PWM(X);
      #endif
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
        _WRITE_CURRENT_PWM(Y);
      #endif
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
        _WRITE_CURRENT_PWM(XY);
      #endif
      break;
    case 1:
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
        _WRITE_CURRENT_PWM(Z);
      #endif
      break;
    case 2:
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
        _WRITE_CURRENT_PWM(E);
      #endif
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0)
        _WRITE_CURRENT_PWM(E0);
      #endif
      #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1)
        _WRITE_CURRENT_PWM(E1);
      #endif
      break;
  }
#endif

}

void Stepper::digipot_init() {

#if HAS_DIGIPOTSS

  static const uint8_t digipot_motor_current[] = DIGIPOT_MOTOR_CURRENT;

  SPI.begin();
  SET_OUTPUT(DIGIPOTSS_PIN);

  for (uint8_t i = 0; i < COUNT(digipot_motor_current); i++) {
    //digitalPotWrite(digipot_ch[i], digipot_motor_current[i]);
    digipot_current(i, digipot_motor_current[i]);
  }

#elif HAS_MOTOR_CURRENT_PWM

  #if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
    SET_OUTPUT(MOTOR_CURRENT_PWM_X_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
    SET_OUTPUT(MOTOR_CURRENT_PWM_Y_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
    SET_OUTPUT(MOTOR_CURRENT_PWM_XY_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
    SET_OUTPUT(MOTOR_CURRENT_PWM_Z_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
    SET_OUTPUT(MOTOR_CURRENT_PWM_E_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_E0)
    SET_OUTPUT(MOTOR_CURRENT_PWM_E0_PIN);
  #endif
  #if PIN_EXISTS(MOTOR_CURRENT_PWM_E1)
    SET_OUTPUT(MOTOR_CURRENT_PWM_E1_PIN);
  #endif

  refresh_motor_power();

  // Set Timer5 to 31khz so the PWM of the motor power is as constant as possible. (removes a buzzing noise)
  #ifdef __AVR__
    SET_CS5(PRESCALER_1);
  #endif
#endif

}

endif

if HAS_MICROSTEPS

/**

endif // HAS_MICROSTEPS

DerAndere1 commented 4 years ago

Thanks, but I cannot find the changes you made. I guess you have to change something in configuration.h . But I would need your complete Marlin source code as a zip to help you. You can make a new comment here using the github web interface. Below the text input field, You will see the message "Attach files by dragging & dropping, selecting or pasting them" . Click on that message and a file browser will open. Use that to attach the zip or place your Source code in a cloud storage like dropbox and send us the link.

hobiseven commented 4 years ago

@nguyennhattam268 Could you post the full marlin code either in a git repository, or here, as a zipfile / drag and drop below please? This would help me, you, and DerAndere1!

Bạn có thể gửi mã marlin đầy đủ trong kho git hoặc ở đây, dưới dạng zipfile / kéo và thả bên dưới không? Điều này sẽ giúp tôi, bạn và DerAndere1!

hobiseven commented 4 years ago

@DerAndere1 I know this will not give 6 axis capabilities, but it seems latest 2.0.1 upwards Marlin release has X2 capability, and that X2 can be fully controlled by Gcode. Does it means that this could be the real 4 axis I look for? There is a Y2 also, but this one is "just" a Y replication.

DerAndere1 commented 4 years ago

@hobiseven : DUAL_X_CARRIAGE can be used for two independent extruders (IDEX). In the following discussion you can find an example config: https://github.com/MarlinFirmware/Marlin/issues/12464 . However you will have to switch between extruders using the G-code comand T0 for tool 0 and T1 for tool 1. So I guess you cannot move axes X1 and X2 simultaneously. If you have more questions regarding existing options, please refer to the following information: https://github.com/MarlinFirmware/Marlin/issues/14694

hobiseven commented 4 years ago

@DerAndere1 I rebuilt the files posted above, as there was many tiny format changes in the comments, highlighting differences, and also some other ones which are rather strange to me like removing the _ in front of AVR ... You will see that he added a few lines of code in both cPP files. New_files.zip

DerAndere1 commented 4 years ago

I added the changes I found plausible. Note that I started the bf2_6axis_dev branch for adding 6 axis support for a minimal setup (no Trinamic drivers, no delta kinematics, no CoreXY kinematics, no EEPPROM, no muti endstops). The latest changes go beyond that and will have to be acompanied with changes in stepper.h, stepper_indirection.h and tmc_util.cpp if you want multi enstops and TMC support. Things might have become rather more broken than fixed.

@nguyennhattam268 : I added you as the author of the last commit in the bf2_6axis_dev branch

hobiseven commented 4 years ago

I started to bring in your code into the Alfawise STM32 code. Will report to you once I will download the code, and give it a try. At least, I will not have a CPU speed issue. it runs at 72Mhz. I renamed all I,J, K axis to U,V,W as those are meant to be secondary axis, and I also saw the issue posted about the names conflicting with some Gcode commands.

DerAndere1 commented 4 years ago

@hobiseven thanks that you take over and incorporate the 6 axis code into a more updated code basis. Don't expect it to work. It will require more work to get the basic test setup going and a huge amount of work to get anything beyond G28 and G1 working with 6 axes. Note that most other firmwares (g2core, smoothie, RRF, Repetier Firmware, grbl-5X etc.) already have 6 axes working, so consider using one of those

hobiseven commented 4 years ago

@DerAndere1 Thank you for the clear warning. Actually, G28 is definitely needed to me, and my Gcode is G1 based. There are a few commands with no 6 axis arguments. Let's see wether or not this will be complicated to get this to work. Typical Gcode is as here :

( Plan XY ) G17 ( SET LENGTH UNITS ) G21 ( SET DISTANCE MODE ) G91 ( SET CUTTER COMPENSATION ) G40 ( SET TOOL LENGTH OFFSET ) G49 ( SET PATH CONTROL MODE ) G64 ( SET FEED RATE MODE ) G94

( Turn on hotwire ) M3 ( Set wire heat using PWM spindle speed [Value relative in %] ) S10 ( Move max speed ) F100 G1 X0 Y20 U0 V20 ( Pause [millisec] ) G4 P2000 ( Move cut speed ) F10 G1 X10 Y0 U10 V0 ( Move cut speed ) G1 X0,482 Y0,694 U0,482 V0,694 G1 X0,911 Y0,792 U0,911 V0,792 .......

I will check wether or not the header commands are all needed... Let's see. but looking at the youtube where we see the A axis turning, ( with a wrong speed), I would hope I am not signing for 10 years effort. I know very well the alfawise board, and Marlin on it.

hobiseven commented 4 years ago

@DerAndere1 I just saw that you have an other branch called marlin2forpipetbot where apparently you use E0 as an axis with an endstop. When you make a g28 do you get x y z e homing? That could be enough for me .... i am half way importing your changes for the 6 axis in marlin 2.0.4.2 . I might need a bit of help to change a few macros that I have a hard time to read...I will open my repo as soon as it compiles.

DerAndere1 commented 4 years ago

hi @hobiseven. I am happy to help with the translation of the macros to "human readable". Some are really cryptic, indeed :D Marlin2ForPipetbot branch should work as intended (endstops + G28 for xyze). I used it on my machine some time ago. I probably removed some temperature code because it is used as lab robot firmware. I also added some artificial(?) feature restrictions using sanity checks to reduce code I had to change. I thought about pointing you to that branch but then thought it wouldn't be the a clean solution. You would need a post processor to translate G1 Xxxx Yyyy Uuuu Vvvv Fnnn syntax into the G1 Xxxx Yyyy Zzzz Eeee Fnnn syntax understood by Marlin2ForPipetBot. Also I think the latter approach would not support G40 or G49. In contrast, with the new 6 axis code it would make sense to later implement G40, G49 and all other G codes currently not supported by Marlin (https://marlinfw.org/meta/gcode/)

DerAndere1 commented 4 years ago

@hobiseven: If you need full support for RS-274 standard compliant 6 axis G-code I still recommend to add support for your board to this HAL-ified grbl fork: https://github.com/terjeio/grblHAL

hobiseven commented 4 years ago

@DerAndere1 Actually I believe G40 and G49 are not needed . The machine is a hot wire cutter and the only requirement is to position the wire at both ends , nothing more. And I do not even need a gcode post processor as the axis names are selectable in jedicut. I have a long rainy week end in front of me to look at this more in depth.

DerAndere1 commented 4 years ago

to get a better overview of the changes that enable e axis homing, see commits https://github.com/MarlinFirmware/Marlin/pull/13076/commits from my rejected PR . There might be one or two bugs in the cleaned up code but those idease are the basis of my working Marlin2ForPipetBot branch

hobiseven commented 4 years ago

Thank you! I will check the pr and your code

hobiseven commented 4 years ago

Indeed, the code changes in your PR https://github.com/MarlinFirmware/Marlin/pull/13076/commits are lot simpler than on the full blown 6 axis compared the last up to date Marlin! Serial.cpp started to be a problem, and there was quite some changes in the Marlin code since you worked on the 6 axis, which makes thing even more complicated. I think E endstop will do the job for me! I will definitely restart on that one.

GabrielBeraldo commented 4 years ago

Hello guys, some time ago i managed to fix all the issues, including eeprom storing and calculate the correct feedrate for all axes, in Cartesian kinematics. I'm using a 12864 lcd display and all the functions for this display was implemented too! Due a personal project and lack of experience in github i changed to my personal repository, now its time to share!

I need some help to port this to the current version of marlin, and this way contribute to the community!

https://github.com/GabrielBeraldo/Marlin/tree/bf2_6axis_dev

Edit: Sorry for my latency in sharing my work, i was really busy finishing my engineering graduation and working on my new business. Now i want to contribute and make this new possibilities accessible to everyone.

hobiseven commented 4 years ago

@GabrielBeraldo hehe this looks a great news to me! So you say that you got this to work including a 12864 lcd... this is nice as our alfawise code uses an 2x zoom of the regular 128x64 marlin screen... I think they call it dogm. Our LCD is a color TFT 320x240, but we use DOGM zoomed in the middle, and we have 4 touchscreen buttons on the bottom, and we have a few flags on the top for BL touch, SD card, filament sensor.

Well seems I have many options now. G28 and g1 working fine for your code?? Or you even made moge Gcodes?

And you do not have to apologize for being late! You are not. We all do those works on the voluntary basis. Thanks for this great piece of work that will for sure please @DerAndere1 .

hobiseven commented 4 years ago

I hope I do check for differences correctly.... The Alfawise maintainned repo is the one of Tpruvot...

https://github.com/tpruvot/Marlin/compare/2.0.4.4-longer3D...GabrielBeraldo:bf2_6axis_dev

@tpruvot is this the right comparaison method. 52 files...

GabrielBeraldo commented 4 years ago

@hobiseven Yes! fully functional G28 and G1. I assume, but not ensure, that all the other commands will work too! This development took me a LOT of debugging with the logic analyzer to figure out where the problem was, not complicate to fix but really hard to find.

GabrielBeraldo commented 4 years ago

I made several mods that will not affect the movimentation factor, like graphical ones. The main differences should be checked in the files that receive, process and execute the moving actions, as well as the endstops and peripheral files linked to G28 execution.

GabrielBeraldo commented 4 years ago

I hope I do check for differences correctly.... The Alfawise maintainned repo is the one of Tpruvot...

tpruvot/Marlin@2.0.4.4-longer3D...GabrielBeraldo:bf2_6axis_dev

@tpruvot is this the right comparaison method. 52 files...

I was not used to work with git, so the commit logic might be messed, but i suggest you to look commit by commit and find the relevant modifications for you. Anyway, i'll be available to help you guys out!

DerAndere1 commented 4 years ago

@GabrielBeraldo Thanks a lot for sharing your fixes. The changes look good! I don't even have a logic analyzer, so thanks for bringing in your engineering expertise.

hobiseven commented 4 years ago

@GabrielBeraldo hi. I have one question regarding axis acceleration management . Have you replicated xyz acceleration to ijk? Or xyz drives the acceleration for the secondary axis?

GabrielBeraldo commented 4 years ago

@GabrielBeraldo hi. I have one question regarding axis acceleration management . Have you replicated xyz acceleration to ijk? Or xyz drives the acceleration for the secondary axis?

All the non extruder axes (XYZ and IJK) has the same privileges and features, like independent Min and Max positions, Min or Max endstops, Feedrates, Accelerations, Jerks and dynamic feedrate calculation when moving alongside with other non extruder axis.

All the parameters can be found in Configuration.h and Configurations_adv.h, in your case:

define DEFAULT_MAX_ACCELERATION { 500, 500, 500, 9, 9, 500 } //X, Y, Z, I, J, K, E

NOTE: this example are only using I and J as additional axes (9 and 9) ,following the extruder acceleration (500), if you wanna use K axis or only I axis, you should add or remove one more parameter before the extruder value. I forgot some traces of my personal development, like the parametric definition of these parameters defined as MODULE_50 and MODULE_20, related to my syringe pump modules of 50mL and 20mL.

hobiseven commented 4 years ago

Ok clear... I was thinking marlin was computing something sort of integral acceleration of the head but likely not! Great job anyhow @GabrielBeraldo

DerAndere1 commented 4 years ago

@hobiseven: This branch adds 6 axis support for the basic kinematics models (cartesian, maybe CORE_XY) where optional steppers I,J,K do not influence positioning of the tool-head. For those setups it manages positioning of the tool-head including junction deviation (or jerk) for controlling the speed at corners for XYZ axes. The additional steppers I, J,K may be used to drive accessories like grippers, pumps etc. For those axes, the speed is controlled using linear acceleration management (linear or sigmoidal acceleration) but no coordination with other axes is done for IJK axes when they are moved simultaneously with other axes. I have no experience but I think that if more than 3 axes are affecting tool-head positioning, you have to take account of the kinematics. I suggest to keep the code for new kinematics out of Marlin and instead develop a post processor that takes the output of your CAM software and calculates the corrected G-code by applying the kinematics for your machine.

DerAndere1 commented 4 years ago

I have a new branch that was rebased on current upstream MarlinFirmware/Marlin bugfix-2.0.x: During the rebase there were so manny conflicts that it was almost a complete rewrite of the 6 axis code. Please test and give feedback: https://github.com/DerAndere1/Marlin/tree/bf2_6axis_dev5

hobiseven commented 4 years ago

Ouaaaa already a version 2? Need to give it a try...

GabrielBeraldo commented 4 years ago

@DerAndere1 Nice! The updates look good! Happy to see this evolving again

DerAndere1 commented 4 years ago

Dont have time to test compile. I expect some typos etc., but we will get there now that Gabriels branch can be used as a reference.

DerAndere1 commented 4 years ago

especially have a look at the parts that have a comment // TODO: Test ... or // TODO: Add support for ... Im AFK, clubbing for the rest of the night.

hobiseven commented 4 years ago

Have fun! I introduced 3/4 of the code in the working tag 2.0.4.2 for my board . The rebase you did has some small issues. 2/3 typos so far. Will do the rest tonight and try to compile. Overall that is quite a lot of changes!

hobiseven commented 4 years ago

Here is Alfawise_Marlin_6_axis code, 2.0.4.4 . There are still some issues to get to compile, even in 3 axis. ... More to come. There are some issues in macros. Marlin-2.0.4.4-longer3D_6axis.zip

DerAndere1 commented 4 years ago

I fixed some compilation errors in my bf2_6axis_dev5 branch. I even have problems compiling bugfix-2.0.x right now. Also there is still a problem with definition of MSG_DWELL and similar MSG_... strings.

hobiseven commented 4 years ago

Well, this is exactly why I use the code with tag 2.0.4.4, as I know this one compiles for my machine, with the custom touch screen and FSMC STM32 LCD. In the rebase you did, there is a mix of changes due to the 6 axis, as well as ongoing changes they do in the live branch.

I am currently stuck there :

Compiling .pio\build\alfawise_U30\src\src\gcode\geometry\G53-G59.cpp.o In file included from Marlin\src\gcode../inc/../core/boards.h:24:0, from Marlin\src\gcode../inc/MarlinConfigPre.h:35, from Marlin\src\gcode../inc/MarlinConfig.h:28, from Marlin\src\gcode\gcode.h:286, from Marlin\src\gcode\gcode.cpp:28: Marlin\src\gcode../inc/../core/macros.h:249:25: error: 'LIST_NUM_AXIS' was not declared in this scope

define _LISTN(N,V...) LIST##N(V)

                     ^

Marlin\src\gcode../inc/../core/macros.h:251:27: note: in expansion of macro '_LIST_N'

define ARRAY_N(N,V...) { _LIST_N(N,V) }

               ^~~~~~~

Marlin\src\gcode../inc/../../Configuration_adv.h:732:29: note: in expansion of macro 'ARRAY_N'

define AXIS_RELATIVE_MODES ARRAY_N(NUM_AXIS, false, false, false, false, false, false, false)

                         ^~~~~~~

Marlin\src\gcode\gcode.cpp:61:40: note: in expansion of macro 'AXIS_RELATIVE_MODES' static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES; ^~~~~~~ Marlin\src\gcode../inc/../core/macros.h:249:25: note: suggested alternative: 'LOOP_NUM_AXIS'

define _LISTN(N,V...) LIST##N(V)

                     ^

Marlin\src\gcode../inc/../core/macros.h:251:27: note: in expansion of macro '_LIST_N'

define ARRAY_N(N,V...) { _LIST_N(N,V) }

                       ^~~~~~~

Marlin\src\gcode../inc/../../Configuration_adv.h:732:29: note: in expansion of macro 'ARRAY_N'

define AXIS_RELATIVE_MODES ARRAY_N(NUM_AXIS, false, false, false, false, false, false, false)

                         ^~~~~~~

Marlin\src\gcode\gcode.cpp:61:40: note: in expansion of macro 'AXIS_RELATIVE_MODES' static constexpr xyze_bool_t ar_init = AXIS_RELATIVE_MODES; ^~~~~~~ *** [.pio\build\alfawise_U30\src\src\gcode\gcode.cpp.o] Error 1

GabrielBeraldo commented 4 years ago

I fixed some compilation errors in my bf2_6axis_dev5 branch. I even have problems compiling bugfix-2.0.x right now. Also there is still a problem with definition of MSG_DWELL and similar MSG_... strings.

is these messages properly defined on language files?

edit: just cloned your dev5 branch and look like the messages are defined, so it must be some import error.

hobiseven commented 4 years ago

I have posted a new git, with the 3 axis compile OK. KO for more axis, as we still have some mistakes / non declarations...

https://github.com/hobiseven/Marlin2.0.4.4_6axis_Longer3D

hobiseven commented 4 years ago

@DerAndere1 I see you are pushing quite some branches... now 6 and 7... Fixing a bit more code each time!?

hobiseven commented 4 years ago

@DerAndere1 now entering in DOGM, and I think that one was never touched so far...

Marlin\src\lcd\dogm\status_screen_DOGM.cpp:393:55: required from here Marlin\src\lcd\dogm../../inc/../core/types.h:864:126: error: could not convert '{((float)((const XYZEval)this)->XYZEval::.XYZEval::::.XYZEval::::::x), ((float)((const XYZEval)this)->XYZEval::.XYZEval::::.XYZEval::::::y), ((float)((const XYZEval)this)->XYZEval::.XYZEval::::.XYZEval::::::z), ((float)((const XYZEval)this)->XYZEval::.XYZEval::::.XYZEval::::::i), ((float)((const XYZEval*)this)->XYZEval::.XYZEval::::.XYZEval::::::e)}' from '' to 'XYZval' C ompiling .pio\build\alfawise_U30\src\src\lcd\dogm\u8g_fontutf8.cpp.o FI XYZval asFloat() const { return { float(x), float(y), float(z), float(i), float(e) }; } Compiling .pio\build\alfawise_U30\src\src\lcd\dogm\ultralcd_DOGM.cpp.o