🧑‍💻 FxdTiCtrl => FTMotion

This commit is contained in:
Scott Lahteine 2023-10-12 09:44:46 -05:00
parent a7a3abb9bf
commit e7e77d9612
12 changed files with 186 additions and 205 deletions

View file

@ -862,7 +862,7 @@ void idle(const bool no_stepper_sleep/*=false*/) {
TERN_(HAS_TFT_LVGL_UI, LV_TASK_HANDLER()); TERN_(HAS_TFT_LVGL_UI, LV_TASK_HANDLER());
// Manage Fixed-time Motion Control // Manage Fixed-time Motion Control
TERN_(FT_MOTION, fxdTiCtrl.loop()); TERN_(FT_MOTION, ftMotion.loop());
IDLE_DONE: IDLE_DONE:
TERN_(MARLIN_DEV_MODE, idle_depth--); TERN_(MARLIN_DEV_MODE, idle_depth--);
@ -1632,7 +1632,7 @@ void setup() {
#endif #endif
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
SETUP_RUN(fxdTiCtrl.init()); SETUP_RUN(ftMotion.init());
#endif #endif
marlin_state = MF_RUNNING; marlin_state = MF_RUNNING;

View file

@ -29,13 +29,13 @@
void say_shaping() { void say_shaping() {
// FT Enabled // FT Enabled
SERIAL_ECHO_TERNARY(fxdTiCtrl.cfg.mode, "Fixed-Time Motion ", "en", "dis", "abled"); SERIAL_ECHO_TERNARY(ftMotion.cfg.mode, "Fixed-Time Motion ", "en", "dis", "abled");
// FT Shaping // FT Shaping
#if HAS_X_AXIS #if HAS_X_AXIS
if (fxdTiCtrl.cfg.mode > ftMotionMode_ENABLED) { if (ftMotion.cfg.mode > ftMotionMode_ENABLED) {
SERIAL_ECHOPGM(" with "); SERIAL_ECHOPGM(" with ");
switch (fxdTiCtrl.cfg.mode) { switch (ftMotion.cfg.mode) {
default: break; default: break;
case ftMotionMode_ZV: SERIAL_ECHOPGM("ZV"); break; case ftMotionMode_ZV: SERIAL_ECHOPGM("ZV"); break;
case ftMotionMode_ZVD: SERIAL_ECHOPGM("ZVD"); break; case ftMotionMode_ZVD: SERIAL_ECHOPGM("ZVD"); break;
@ -51,15 +51,15 @@ void say_shaping() {
#endif #endif
SERIAL_ECHOLNPGM("."); SERIAL_ECHOLNPGM(".");
const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_Z_BASED), const bool z_based = TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED),
g_based = TERN0(HAS_DYNAMIC_FREQ_G, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_MASS_BASED), g_based = TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED),
dynamic = z_based || g_based; dynamic = z_based || g_based;
// FT Dynamic Frequency Mode // FT Dynamic Frequency Mode
if (fxdTiCtrl.cfg.modeHasShaper()) { if (ftMotion.cfg.modeHasShaper()) {
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
SERIAL_ECHOPGM("Dynamic Frequency Mode "); SERIAL_ECHOPGM("Dynamic Frequency Mode ");
switch (fxdTiCtrl.cfg.dynFreqMode) { switch (ftMotion.cfg.dynFreqMode) {
default: default:
case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break; case dynFreqMode_DISABLED: SERIAL_ECHOPGM("disabled"); break;
#if HAS_DYNAMIC_FREQ_MM #if HAS_DYNAMIC_FREQ_MM
@ -74,32 +74,32 @@ void say_shaping() {
#if HAS_X_AXIS #if HAS_X_AXIS
SERIAL_ECHO_TERNARY(dynamic, "X/A ", "base dynamic", "static", " compensator frequency: "); SERIAL_ECHO_TERNARY(dynamic, "X/A ", "base dynamic", "static", " compensator frequency: ");
SERIAL_ECHO(p_float_t(fxdTiCtrl.cfg.baseFreq[X_AXIS], 2), F("Hz")); SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[X_AXIS], 2), F("Hz"));
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
if (dynamic) SERIAL_ECHO(" scaling: ", p_float_t(fxdTiCtrl.cfg.dynFreqK[X_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g")); if (dynamic) SERIAL_ECHO(" scaling: ", p_float_t(ftMotion.cfg.dynFreqK[X_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g"));
#endif #endif
SERIAL_EOL(); SERIAL_EOL();
#endif #endif
#if HAS_Y_AXIS #if HAS_Y_AXIS
SERIAL_ECHO_TERNARY(dynamic, "Y/B ", "base dynamic", "static", " compensator frequency: "); SERIAL_ECHO_TERNARY(dynamic, "Y/B ", "base dynamic", "static", " compensator frequency: ");
SERIAL_ECHO(p_float_t(fxdTiCtrl.cfg.baseFreq[Y_AXIS], 2), F(" Hz")); SERIAL_ECHO(p_float_t(ftMotion.cfg.baseFreq[Y_AXIS], 2), F(" Hz"));
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(fxdTiCtrl.cfg.dynFreqK[Y_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g")); if (dynamic) SERIAL_ECHO(F(" scaling: "), p_float_t(ftMotion.cfg.dynFreqK[Y_AXIS], 8), F("Hz/"), z_based ? F("mm") : F("g"));
#endif #endif
SERIAL_EOL(); SERIAL_EOL();
#endif #endif
} }
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
SERIAL_ECHO_TERNARY(fxdTiCtrl.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled"); SERIAL_ECHO_TERNARY(ftMotion.cfg.linearAdvEna, "Linear Advance ", "en", "dis", "abled");
SERIAL_ECHOLN(F(". Gain: "), p_float_t(fxdTiCtrl.cfg.linearAdvK, 5)); SERIAL_ECHOLN(F(". Gain: "), p_float_t(ftMotion.cfg.linearAdvK, 5));
#endif #endif
} }
void GcodeSuite::M493_report(const bool forReplay/*=true*/) { void GcodeSuite::M493_report(const bool forReplay/*=true*/) {
report_heading_etc(forReplay, F(STR_FT_MOTION)); report_heading_etc(forReplay, F(STR_FT_MOTION));
const ft_config_t &c = fxdTiCtrl.cfg; const ft_config_t &c = ftMotion.cfg;
SERIAL_ECHOPGM(" M493 S", c.mode); SERIAL_ECHOPGM(" M493 S", c.mode);
#if HAS_X_AXIS #if HAS_X_AXIS
SERIAL_ECHOPGM(" A", c.baseFreq[X_AXIS]); SERIAL_ECHOPGM(" A", c.baseFreq[X_AXIS]);
@ -160,7 +160,7 @@ void GcodeSuite::M493() {
// Parse 'S' mode parameter. // Parse 'S' mode parameter.
if (parser.seenval('S')) { if (parser.seenval('S')) {
const ftMotionMode_t oldmm = fxdTiCtrl.cfg.mode, const ftMotionMode_t oldmm = ftMotion.cfg.mode,
newmm = (ftMotionMode_t)parser.value_byte(); newmm = (ftMotionMode_t)parser.value_byte();
if (newmm != oldmm) { if (newmm != oldmm) {
@ -179,7 +179,7 @@ void GcodeSuite::M493() {
#endif #endif
case ftMotionMode_DISABLED: case ftMotionMode_DISABLED:
case ftMotionMode_ENABLED: case ftMotionMode_ENABLED:
fxdTiCtrl.cfg.mode = newmm; ftMotion.cfg.mode = newmm;
flag.report_h = true; flag.report_h = true;
if (oldmm == ftMotionMode_DISABLED) flag.reset_ft = true; if (oldmm == ftMotionMode_DISABLED) flag.reset_ft = true;
break; break;
@ -192,7 +192,7 @@ void GcodeSuite::M493() {
// Pressure control (linear advance) parameter. // Pressure control (linear advance) parameter.
if (parser.seen('P')) { if (parser.seen('P')) {
const bool val = parser.value_bool(); const bool val = parser.value_bool();
fxdTiCtrl.cfg.linearAdvEna = val; ftMotion.cfg.linearAdvEna = val;
SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n"); SERIAL_ECHO_TERNARY(val, "Linear Advance ", "en", "dis", "abled.\n");
} }
@ -200,7 +200,7 @@ void GcodeSuite::M493() {
if (parser.seenval('K')) { if (parser.seenval('K')) {
const float val = parser.value_float(); const float val = parser.value_float();
if (val >= 0.0f) { if (val >= 0.0f) {
fxdTiCtrl.cfg.linearAdvK = val; ftMotion.cfg.linearAdvK = val;
flag.report_h = true; flag.report_h = true;
} }
else // Value out of range. else // Value out of range.
@ -213,22 +213,22 @@ void GcodeSuite::M493() {
// Dynamic frequency mode parameter. // Dynamic frequency mode parameter.
if (parser.seenval('D')) { if (parser.seenval('D')) {
if (fxdTiCtrl.cfg.modeHasShaper()) { if (ftMotion.cfg.modeHasShaper()) {
const dynFreqMode_t val = dynFreqMode_t(parser.value_byte()); const dynFreqMode_t val = dynFreqMode_t(parser.value_byte());
switch (val) { switch (val) {
case dynFreqMode_DISABLED: case dynFreqMode_DISABLED:
fxdTiCtrl.cfg.dynFreqMode = val; ftMotion.cfg.dynFreqMode = val;
flag.report_h = true; flag.report_h = true;
break; break;
#if HAS_DYNAMIC_FREQ_MM #if HAS_DYNAMIC_FREQ_MM
case dynFreqMode_Z_BASED: case dynFreqMode_Z_BASED:
fxdTiCtrl.cfg.dynFreqMode = val; ftMotion.cfg.dynFreqMode = val;
flag.report_h = true; flag.report_h = true;
break; break;
#endif #endif
#if HAS_DYNAMIC_FREQ_G #if HAS_DYNAMIC_FREQ_G
case dynFreqMode_MASS_BASED: case dynFreqMode_MASS_BASED:
fxdTiCtrl.cfg.dynFreqMode = val; ftMotion.cfg.dynFreqMode = val;
flag.report_h = true; flag.report_h = true;
break; break;
#endif #endif
@ -243,8 +243,8 @@ void GcodeSuite::M493() {
} }
const bool modeUsesDynFreq = ( const bool modeUsesDynFreq = (
TERN0(HAS_DYNAMIC_FREQ_MM, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_Z_BASED) TERN0(HAS_DYNAMIC_FREQ_MM, ftMotion.cfg.dynFreqMode == dynFreqMode_Z_BASED)
|| TERN0(HAS_DYNAMIC_FREQ_G, fxdTiCtrl.cfg.dynFreqMode == dynFreqMode_MASS_BASED) || TERN0(HAS_DYNAMIC_FREQ_G, ftMotion.cfg.dynFreqMode == dynFreqMode_MASS_BASED)
); );
#endif // HAS_DYNAMIC_FREQ #endif // HAS_DYNAMIC_FREQ
@ -253,11 +253,11 @@ void GcodeSuite::M493() {
// Parse frequency parameter (X axis). // Parse frequency parameter (X axis).
if (parser.seenval('A')) { if (parser.seenval('A')) {
if (fxdTiCtrl.cfg.modeHasShaper()) { if (ftMotion.cfg.modeHasShaper()) {
const float val = parser.value_float(); const float val = parser.value_float();
// TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct. // TODO: Frequency minimum is dependent on the shaper used; the above check isn't always correct.
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
fxdTiCtrl.cfg.baseFreq[X_AXIS] = val; ftMotion.cfg.baseFreq[X_AXIS] = val;
flag.update_n = flag.reset_ft = flag.report_h = true; flag.update_n = flag.reset_ft = flag.report_h = true;
} }
else // Frequency out of range. else // Frequency out of range.
@ -271,7 +271,7 @@ void GcodeSuite::M493() {
// Parse frequency scaling parameter (X axis). // Parse frequency scaling parameter (X axis).
if (parser.seenval('F')) { if (parser.seenval('F')) {
if (modeUsesDynFreq) { if (modeUsesDynFreq) {
fxdTiCtrl.cfg.dynFreqK[X_AXIS] = parser.value_float(); ftMotion.cfg.dynFreqK[X_AXIS] = parser.value_float();
flag.report_h = true; flag.report_h = true;
} }
else else
@ -285,10 +285,10 @@ void GcodeSuite::M493() {
// Parse frequency parameter (Y axis). // Parse frequency parameter (Y axis).
if (parser.seenval('B')) { if (parser.seenval('B')) {
if (fxdTiCtrl.cfg.modeHasShaper()) { if (ftMotion.cfg.modeHasShaper()) {
const float val = parser.value_float(); const float val = parser.value_float();
if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) { if (WITHIN(val, FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2)) {
fxdTiCtrl.cfg.baseFreq[Y_AXIS] = val; ftMotion.cfg.baseFreq[Y_AXIS] = val;
flag.update_n = flag.reset_ft = flag.report_h = true; flag.update_n = flag.reset_ft = flag.report_h = true;
} }
else // Frequency out of range. else // Frequency out of range.
@ -302,7 +302,7 @@ void GcodeSuite::M493() {
// Parse frequency scaling parameter (Y axis). // Parse frequency scaling parameter (Y axis).
if (parser.seenval('H')) { if (parser.seenval('H')) {
if (modeUsesDynFreq) { if (modeUsesDynFreq) {
fxdTiCtrl.cfg.dynFreqK[Y_AXIS] = parser.value_float(); ftMotion.cfg.dynFreqK[Y_AXIS] = parser.value_float();
flag.report_h = true; flag.report_h = true;
} }
else else
@ -313,10 +313,10 @@ void GcodeSuite::M493() {
#endif // HAS_Y_AXIS #endif // HAS_Y_AXIS
#if HAS_X_AXIS #if HAS_X_AXIS
if (flag.update_n) fxdTiCtrl.refreshShapingN(); if (flag.update_n) ftMotion.refreshShapingN();
if (flag.update_a) fxdTiCtrl.updateShapingA(); if (flag.update_a) ftMotion.updateShapingA();
#endif #endif
if (flag.reset_ft) fxdTiCtrl.reset(); if (flag.reset_ft) ftMotion.reset();
if (flag.report_h) say_shaping(); if (flag.report_h) say_shaping();
} }

View file

@ -319,13 +319,13 @@ void menu_move() {
#include "../../gcode/gcode.h" #include "../../gcode/gcode.h"
void ftm_menu_setShaping(const ftMotionMode_t s) { void ftm_menu_setShaping(const ftMotionMode_t s) {
fxdTiCtrl.cfg.mode = s; ftMotion.cfg.mode = s;
fxdTiCtrl.refreshShapingN(); ftMotion.refreshShapingN();
ui.go_back(); ui.go_back();
} }
inline void menu_ftm_mode() { inline void menu_ftm_mode() {
const ftMotionMode_t mode = fxdTiCtrl.cfg.mode; const ftMotionMode_t mode = ftMotion.cfg.mode;
START_MENU(); START_MENU();
BACK_ITEM(MSG_FIXED_TIME_MOTION); BACK_ITEM(MSG_FIXED_TIME_MOTION);
@ -349,17 +349,17 @@ void menu_move() {
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
inline void menu_ftm_dyn_mode() { inline void menu_ftm_dyn_mode() {
const dynFreqMode_t dmode = fxdTiCtrl.cfg.dynFreqMode; const dynFreqMode_t dmode = ftMotion.cfg.dynFreqMode;
START_MENU(); START_MENU();
BACK_ITEM(MSG_FIXED_TIME_MOTION); BACK_ITEM(MSG_FIXED_TIME_MOTION);
if (dmode != dynFreqMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ fxdTiCtrl.cfg.dynFreqMode = dynFreqMode_DISABLED; ui.go_back(); }); if (dmode != dynFreqMode_DISABLED) ACTION_ITEM(MSG_LCD_OFF, []{ ftMotion.cfg.dynFreqMode = dynFreqMode_DISABLED; ui.go_back(); });
#if HAS_DYNAMIC_FREQ_MM #if HAS_DYNAMIC_FREQ_MM
if (dmode != dynFreqMode_Z_BASED) ACTION_ITEM(MSG_FTM_Z_BASED, []{ fxdTiCtrl.cfg.dynFreqMode = dynFreqMode_Z_BASED; ui.go_back(); }); if (dmode != dynFreqMode_Z_BASED) ACTION_ITEM(MSG_FTM_Z_BASED, []{ ftMotion.cfg.dynFreqMode = dynFreqMode_Z_BASED; ui.go_back(); });
#endif #endif
#if HAS_DYNAMIC_FREQ_G #if HAS_DYNAMIC_FREQ_G
if (dmode != dynFreqMode_MASS_BASED) ACTION_ITEM(MSG_FTM_MASS_BASED, []{ fxdTiCtrl.cfg.dynFreqMode = dynFreqMode_MASS_BASED; ui.go_back(); }); if (dmode != dynFreqMode_MASS_BASED) ACTION_ITEM(MSG_FTM_MASS_BASED, []{ ftMotion.cfg.dynFreqMode = dynFreqMode_MASS_BASED; ui.go_back(); });
#endif #endif
END_MENU(); END_MENU();
@ -368,7 +368,7 @@ void menu_move() {
#endif // HAS_DYNAMIC_FREQ #endif // HAS_DYNAMIC_FREQ
void menu_ft_motion() { void menu_ft_motion() {
ft_config_t &c = fxdTiCtrl.cfg; ft_config_t &c = ftMotion.cfg;
FSTR_P ftmode; FSTR_P ftmode;
switch (c.mode) { switch (c.mode) {
@ -403,16 +403,16 @@ void menu_move() {
if (c.modeHasShaper()) { if (c.modeHasShaper()) {
#if HAS_X_AXIS #if HAS_X_AXIS
EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[X_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, fxdTiCtrl.refreshShapingN); EDIT_ITEM_FAST_N(float42_52, X_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[X_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.refreshShapingN);
#endif #endif
#if HAS_Y_AXIS #if HAS_Y_AXIS
EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[Y_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, fxdTiCtrl.refreshShapingN); EDIT_ITEM_FAST_N(float42_52, Y_AXIS, MSG_FTM_BASE_FREQ_N, &c.baseFreq[Y_AXIS], FTM_MIN_SHAPE_FREQ, (FTM_FS) / 2, ftMotion.refreshShapingN);
#endif #endif
EDIT_ITEM_FAST(float42_52, MSG_FTM_ZETA, &c.zeta, 0.0f, 1.0f, fxdTiCtrl.refreshShapingN); EDIT_ITEM_FAST(float42_52, MSG_FTM_ZETA, &c.zeta, 0.0f, 1.0f, ftMotion.refreshShapingN);
if (WITHIN(c.mode, ftMotionMode_EI, ftMotionMode_3HEI)) if (WITHIN(c.mode, ftMotionMode_EI, ftMotionMode_3HEI))
EDIT_ITEM_FAST(float42_52, MSG_FTM_VTOL, &c.vtol, 0.0f, 1.0f, fxdTiCtrl.refreshShapingN); EDIT_ITEM_FAST(float42_52, MSG_FTM_VTOL, &c.vtol, 0.0f, 1.0f, ftMotion.refreshShapingN);
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
SUBMENU(MSG_FTM_DYN_MODE, menu_ftm_dyn_mode); SUBMENU(MSG_FTM_DYN_MODE, menu_ftm_dyn_mode);

View file

@ -27,7 +27,7 @@
#include "ft_motion.h" #include "ft_motion.h"
#include "stepper.h" // Access stepper block queue function and abort status. #include "stepper.h" // Access stepper block queue function and abort status.
FxdTiCtrl fxdTiCtrl; FTMotion ftMotion;
#if !HAS_X_AXIS #if !HAS_X_AXIS
static_assert(FTM_DEFAULT_MODE == ftMotionMode_ZV, "ftMotionMode_ZV requires at least one linear axis."); static_assert(FTM_DEFAULT_MODE == ftMotionMode_ZV, "ftMotionMode_ZV requires at least one linear axis.");
@ -50,66 +50,67 @@ FxdTiCtrl fxdTiCtrl;
// Public variables. // Public variables.
ft_config_t FxdTiCtrl::cfg; ft_config_t FTMotion::cfg;
ft_command_t FxdTiCtrl::stepperCmdBuff[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of stepper commands. bool FTMotion::busy; // = false
hal_timer_t FxdTiCtrl::stepperCmdBuff_StepRelativeTi[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of the stepper command timing. ft_command_t FTMotion::stepperCmdBuff[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of stepper commands.
uint8_t FxdTiCtrl::stepperCmdBuff_ApplyDir[FTM_STEPPERCMD_DIR_SIZE] = {0U}; // Buffer of whether DIR needs to be updated. hal_timer_t FTMotion::stepperCmdBuff_StepRelativeTi[FTM_STEPPERCMD_BUFF_SIZE] = {0U}; // Buffer of the stepper command timing.
uint32_t FxdTiCtrl::stepperCmdBuff_produceIdx = 0, // Index of next stepper command write to the buffer. uint8_t FTMotion::stepperCmdBuff_ApplyDir[FTM_STEPPERCMD_DIR_SIZE] = {0U}; // Buffer of whether DIR needs to be updated.
FxdTiCtrl::stepperCmdBuff_consumeIdx = 0; // Index of next stepper command read from the buffer. uint32_t FTMotion::stepperCmdBuff_produceIdx = 0, // Index of next stepper command write to the buffer.
FTMotion::stepperCmdBuff_consumeIdx = 0; // Index of next stepper command read from the buffer.
bool FxdTiCtrl::sts_stepperBusy = false; // The stepper buffer has items and is in use. bool FTMotion::sts_stepperBusy = false; // The stepper buffer has items and is in use.
// Private variables. // Private variables.
// NOTE: These are sized for Ulendo FBS use. // NOTE: These are sized for Ulendo FBS use.
xyze_trajectory_t FxdTiCtrl::traj; // = {0.0f} Storage for fixed-time-based trajectory. xyze_trajectory_t FTMotion::traj; // = {0.0f} Storage for fixed-time-based trajectory.
xyze_trajectoryMod_t FxdTiCtrl::trajMod; // = {0.0f} Storage for modified fixed-time-based trajectory. xyze_trajectoryMod_t FTMotion::trajMod; // = {0.0f} Storage for modified fixed-time-based trajectory.
block_t* FxdTiCtrl::current_block_cpy = nullptr; // Pointer to current block being processed. block_t* FTMotion::current_block_cpy = nullptr; // Pointer to current block being processed.
bool FxdTiCtrl::blockProcRdy = false, // Indicates a block is ready to be processed. bool FTMotion::blockProcRdy = false, // Indicates a block is ready to be processed.
FxdTiCtrl::blockProcRdy_z1 = false, // Storage for the previous indicator. FTMotion::blockProcRdy_z1 = false, // Storage for the previous indicator.
FxdTiCtrl::blockProcDn = false; // Indicates current block is done being processed. FTMotion::blockProcDn = false; // Indicates current block is done being processed.
bool FxdTiCtrl::batchRdy = false; // Indicates a batch of the fixed time trajectory bool FTMotion::batchRdy = false; // Indicates a batch of the fixed time trajectory
// has been generated, is now available in the upper - // has been generated, is now available in the upper -
// half of traj.x[], y, z ... e vectors, and is ready to be // half of traj.x[], y, z ... e vectors, and is ready to be
// post processed, if applicable, then interpolated. // post processed, if applicable, then interpolated.
bool FxdTiCtrl::batchRdyForInterp = false; // Indicates the batch is done being post processed, bool FTMotion::batchRdyForInterp = false; // Indicates the batch is done being post processed,
// if applicable, and is ready to be converted to step commands. // if applicable, and is ready to be converted to step commands.
bool FxdTiCtrl::runoutEna = false; // True if runout of the block hasn't been done and is allowed. bool FTMotion::runoutEna = false; // True if runout of the block hasn't been done and is allowed.
bool FxdTiCtrl::runout = false; // Indicates if runout is in progress. bool FTMotion::runout = false; // Indicates if runout is in progress.
// Trapezoid data variables. // Trapezoid data variables.
xyze_pos_t FxdTiCtrl::startPosn, // (mm) Start position of block xyze_pos_t FTMotion::startPosn, // (mm) Start position of block
FxdTiCtrl::endPosn_prevBlock = { 0.0f }; // (mm) End position of previous block FTMotion::endPosn_prevBlock = { 0.0f }; // (mm) End position of previous block
xyze_float_t FxdTiCtrl::ratio; // (ratio) Axis move ratio of block xyze_float_t FTMotion::ratio; // (ratio) Axis move ratio of block
float FxdTiCtrl::accel_P, // Acceleration prime of block. [mm/sec/sec] float FTMotion::accel_P, // Acceleration prime of block. [mm/sec/sec]
FxdTiCtrl::decel_P, // Deceleration prime of block. [mm/sec/sec] FTMotion::decel_P, // Deceleration prime of block. [mm/sec/sec]
FxdTiCtrl::F_P, // Feedrate prime of block. [mm/sec] FTMotion::F_P, // Feedrate prime of block. [mm/sec]
FxdTiCtrl::f_s, // Starting feedrate of block. [mm/sec] FTMotion::f_s, // Starting feedrate of block. [mm/sec]
FxdTiCtrl::s_1e, // Position after acceleration phase of block. FTMotion::s_1e, // Position after acceleration phase of block.
FxdTiCtrl::s_2e; // Position after acceleration and coasting phase of block. FTMotion::s_2e; // Position after acceleration and coasting phase of block.
uint32_t FxdTiCtrl::N1, // Number of data points in the acceleration phase. uint32_t FTMotion::N1, // Number of data points in the acceleration phase.
FxdTiCtrl::N2, // Number of data points in the coasting phase. FTMotion::N2, // Number of data points in the coasting phase.
FxdTiCtrl::N3; // Number of data points in the deceleration phase. FTMotion::N3; // Number of data points in the deceleration phase.
uint32_t FxdTiCtrl::max_intervals; // Total number of data points that will be generated from block. uint32_t FTMotion::max_intervals; // Total number of data points that will be generated from block.
// Make vector variables. // Make vector variables.
uint32_t FxdTiCtrl::makeVector_idx = 0, // Index of fixed time trajectory generation of the overall block. uint32_t FTMotion::makeVector_idx = 0, // Index of fixed time trajectory generation of the overall block.
FxdTiCtrl::makeVector_idx_z1 = 0, // Storage for the previously calculated index above. FTMotion::makeVector_idx_z1 = 0, // Storage for the previously calculated index above.
FxdTiCtrl::makeVector_batchIdx = FTM_BATCH_SIZE; // Index of fixed time trajectory generation within the batch. FTMotion::makeVector_batchIdx = FTM_BATCH_SIZE; // Index of fixed time trajectory generation within the batch.
// Interpolation variables. // Interpolation variables.
xyze_long_t FxdTiCtrl::steps = { 0 }; // Step count accumulator. xyze_long_t FTMotion::steps = { 0 }; // Step count accumulator.
xyze_stepDir_t FxdTiCtrl::dirState = LOGICAL_AXIS_ARRAY_1(stepDirState_NOT_SET); // Memory of the currently set step direction of the axis. xyze_stepDir_t FTMotion::dirState = LOGICAL_AXIS_ARRAY_1(stepDirState_NOT_SET); // Memory of the currently set step direction of the axis.
uint32_t FxdTiCtrl::interpIdx = 0, // Index of current data point being interpolated. uint32_t FTMotion::interpIdx = 0, // Index of current data point being interpolated.
FxdTiCtrl::interpIdx_z1 = 0; // Storage for the previously calculated index above. FTMotion::interpIdx_z1 = 0; // Storage for the previously calculated index above.
hal_timer_t FxdTiCtrl::nextStepTicks = FTM_MIN_TICKS; // Accumulator for the next step time (in ticks). hal_timer_t FTMotion::nextStepTicks = FTM_MIN_TICKS; // Accumulator for the next step time (in ticks).
// Shaping variables. // Shaping variables.
#if HAS_X_AXIS #if HAS_X_AXIS
FxdTiCtrl::shaping_t FxdTiCtrl::shaping = { FTMotion::shaping_t FTMotion::shaping = {
0, 0, 0, 0,
x:{ { 0.0f }, { 0.0f }, { 0 } }, // d_zi, Ai, Ni x:{ { 0.0f }, { 0.0f }, { 0 } }, // d_zi, Ai, Ni
#if HAS_Y_AXIS #if HAS_Y_AXIS
@ -120,8 +121,8 @@ hal_timer_t FxdTiCtrl::nextStepTicks = FTM_MIN_TICKS; // Accumulator for the nex
#if HAS_EXTRUDERS #if HAS_EXTRUDERS
// Linear advance variables. // Linear advance variables.
float FxdTiCtrl::e_raw_z1 = 0.0f; // (ms) Unit delay of raw extruder position. float FTMotion::e_raw_z1 = 0.0f; // (ms) Unit delay of raw extruder position.
float FxdTiCtrl::e_advanced_z1 = 0.0f; // (ms) Unit delay of advanced extruder position. float FTMotion::e_advanced_z1 = 0.0f; // (ms) Unit delay of advanced extruder position.
#endif #endif
constexpr uint32_t last_batchIdx = (FTM_WINDOW_SIZE) - (FTM_BATCH_SIZE); constexpr uint32_t last_batchIdx = (FTM_WINDOW_SIZE) - (FTM_BATCH_SIZE);
@ -133,15 +134,15 @@ constexpr uint32_t last_batchIdx = (FTM_WINDOW_SIZE) - (FTM_BATCH_SIZE);
// Public functions. // Public functions.
// Sets controller states to begin processing a block. // Sets controller states to begin processing a block.
void FxdTiCtrl::startBlockProc(block_t * const current_block) { void FTMotion::startBlockProc(block_t * const current_block) {
current_block_cpy = current_block; current_block_cpy = current_block;
blockProcRdy = true; blockProcRdy = true;
blockProcDn = false; blockProcDn = false;
runoutEna = true; runoutEna = true;
} }
// Moves any free data points to the stepper buffer even if a full batch isn't ready. // Move any free data points to the stepper buffer even if a full batch isn't ready.
void FxdTiCtrl::runoutBlock() { void FTMotion::runoutBlock() {
if (runoutEna && !batchRdy) { // If the window is full already (block intervals was a multiple of if (runoutEna && !batchRdy) { // If the window is full already (block intervals was a multiple of
// the batch size), or runout is not enabled, no runout is needed. // the batch size), or runout is not enabled, no runout is needed.
@ -170,7 +171,7 @@ void FxdTiCtrl::runoutBlock() {
} }
// Controller main, to be invoked from non-isr task. // Controller main, to be invoked from non-isr task.
void FxdTiCtrl::loop() { void FTMotion::loop() {
if (!cfg.mode) return; if (!cfg.mode) return;
@ -188,7 +189,7 @@ void FxdTiCtrl::loop() {
} }
// Planner processing and block conversion. // Planner processing and block conversion.
if (!blockProcRdy && !runout) stepper.fxdTiCtrl_BlockQueueUpdate(); if (!blockProcRdy && !runout) stepper.ftMotion_BlockQueueUpdate();
if (blockProcRdy) { if (blockProcRdy) {
if (!blockProcRdy_z1) loadBlockData(current_block_cpy); // One-shot. if (!blockProcRdy_z1) loadBlockData(current_block_cpy); // One-shot.
@ -264,7 +265,7 @@ void FxdTiCtrl::loop() {
} }
// Report busy status to planner. // Report busy status to planner.
planner.fxdTiCtrl_busy = (sts_stepperBusy || ((!blockProcDn && blockProcRdy) || batchRdy || batchRdyForInterp || runoutEna)); busy = (sts_stepperBusy || ((!blockProcDn && blockProcRdy) || batchRdy || batchRdyForInterp || runoutEna));
blockProcRdy_z1 = blockProcRdy; blockProcRdy_z1 = blockProcRdy;
makeVector_idx_z1 = makeVector_idx; makeVector_idx_z1 = makeVector_idx;
@ -276,7 +277,7 @@ void FxdTiCtrl::loop() {
// Refresh the gains used by shaping functions. // Refresh the gains used by shaping functions.
// To be called on init or mode or zeta change. // To be called on init or mode or zeta change.
void FxdTiCtrl::Shaping::updateShapingA(const_float_t zeta/*=cfg.zeta*/, const_float_t vtol/*=cfg.vtol*/) { void FTMotion::Shaping::updateShapingA(const_float_t zeta/*=cfg.zeta*/, const_float_t vtol/*=cfg.vtol*/) {
const float K = exp(-zeta * M_PI / sqrt(1.0f - sq(zeta))), const float K = exp(-zeta * M_PI / sqrt(1.0f - sq(zeta))),
K2 = sq(K); K2 = sq(K);
@ -345,14 +346,14 @@ void FxdTiCtrl::loop() {
#endif #endif
} }
void FxdTiCtrl::updateShapingA(const_float_t zeta/*=cfg.zeta*/, const_float_t vtol/*=cfg.vtol*/) { void FTMotion::updateShapingA(const_float_t zeta/*=cfg.zeta*/, const_float_t vtol/*=cfg.vtol*/) {
shaping.updateShapingA(zeta, vtol); shaping.updateShapingA(zeta, vtol);
} }
// Refresh the indices used by shaping functions. // Refresh the indices used by shaping functions.
// To be called when frequencies change. // To be called when frequencies change.
void FxdTiCtrl::AxisShaping::updateShapingN(const_float_t f, const_float_t df) { void FTMotion::AxisShaping::updateShapingN(const_float_t f, const_float_t df) {
// Protections omitted for DBZ and for index exceeding array length. // Protections omitted for DBZ and for index exceeding array length.
switch (cfg.mode) { switch (cfg.mode) {
case ftMotionMode_ZV: case ftMotionMode_ZV:
@ -382,7 +383,7 @@ void FxdTiCtrl::loop() {
} }
} }
void FxdTiCtrl::updateShapingN(const_float_t xf OPTARG(HAS_Y_AXIS, const_float_t yf), const_float_t zeta/*=cfg.zeta*/) { void FTMotion::updateShapingN(const_float_t xf OPTARG(HAS_Y_AXIS, const_float_t yf), const_float_t zeta/*=cfg.zeta*/) {
const float df = sqrt(1.0f - sq(zeta)); const float df = sqrt(1.0f - sq(zeta));
shaping.x.updateShapingN(xf, df); shaping.x.updateShapingN(xf, df);
TERN_(HAS_Y_AXIS, shaping.y.updateShapingN(yf, df)); TERN_(HAS_Y_AXIS, shaping.y.updateShapingN(yf, df));
@ -391,12 +392,12 @@ void FxdTiCtrl::loop() {
#endif // HAS_X_AXIS #endif // HAS_X_AXIS
// Reset all trajectory processing variables. // Reset all trajectory processing variables.
void FxdTiCtrl::reset() { void FTMotion::reset() {
stepperCmdBuff_produceIdx = stepperCmdBuff_consumeIdx = 0; stepperCmdBuff_produceIdx = stepperCmdBuff_consumeIdx = 0;
traj.reset(); // Reset trajectory history traj.reset(); // Reset trajectory history
trajMod.reset(); // Reset modified trajectory history trajMod.reset(); // Reset modified trajectory history
blockProcRdy = blockProcRdy_z1 = blockProcDn = false; blockProcRdy = blockProcRdy_z1 = blockProcDn = false;
batchRdy = batchRdyForInterp = false; batchRdy = batchRdyForInterp = false;
@ -424,13 +425,13 @@ void FxdTiCtrl::reset() {
// Private functions. // Private functions.
// Auxiliary function to get number of step commands in the buffer. // Auxiliary function to get number of step commands in the buffer.
uint32_t FxdTiCtrl::stepperCmdBuffItems() { uint32_t FTMotion::stepperCmdBuffItems() {
const uint32_t udiff = stepperCmdBuff_produceIdx - stepperCmdBuff_consumeIdx; const uint32_t udiff = stepperCmdBuff_produceIdx - stepperCmdBuff_consumeIdx;
return stepperCmdBuff_produceIdx < stepperCmdBuff_consumeIdx ? (FTM_STEPPERCMD_BUFF_SIZE) + udiff : udiff; return stepperCmdBuff_produceIdx < stepperCmdBuff_consumeIdx ? (FTM_STEPPERCMD_BUFF_SIZE) + udiff : udiff;
} }
// Initializes storage variables before startup. // Initializes storage variables before startup.
void FxdTiCtrl::init() { void FTMotion::init() {
#if HAS_X_AXIS #if HAS_X_AXIS
refreshShapingN(); refreshShapingN();
updateShapingA(); updateShapingA();
@ -439,7 +440,7 @@ void FxdTiCtrl::init() {
} }
// Loads / converts block data from planner to fixed-time control variables. // Loads / converts block data from planner to fixed-time control variables.
void FxdTiCtrl::loadBlockData(block_t * const current_block) { void FTMotion::loadBlockData(block_t * const current_block) {
const float totalLength = current_block->millimeters, const float totalLength = current_block->millimeters,
oneOverLength = 1.0f / totalLength; oneOverLength = 1.0f / totalLength;
@ -489,6 +490,7 @@ void FxdTiCtrl::loadBlockData(block_t * const current_block) {
const float fdiff = feSqByTwoD - fsSqByTwoA, // (mm) Coasting distance if nominal speed is reached const float fdiff = feSqByTwoD - fsSqByTwoA, // (mm) Coasting distance if nominal speed is reached
odiff = oneby2a - oneby2d, // (i.e., oneby2a * 2) (mm/s) Change in speed for one second of acceleration odiff = oneby2a - oneby2d, // (i.e., oneby2a * 2) (mm/s) Change in speed for one second of acceleration
ldiff = totalLength - fdiff; // (mm) Distance to travel if nominal speed is reached ldiff = totalLength - fdiff; // (mm) Distance to travel if nominal speed is reached
float T2 = (1.0f / F_n) * (ldiff - odiff * sq(F_n)); // (s) Coasting duration after nominal speed reached float T2 = (1.0f / F_n) * (ldiff - odiff * sq(F_n)); // (s) Coasting duration after nominal speed reached
if (T2 < 0.0f) { if (T2 < 0.0f) {
T2 = 0.0f; T2 = 0.0f;
@ -496,7 +498,6 @@ void FxdTiCtrl::loadBlockData(block_t * const current_block) {
} }
const float T1 = (F_n - f_s) / a, // (s) Accel Time = difference in feedrate over acceleration const float T1 = (F_n - f_s) / a, // (s) Accel Time = difference in feedrate over acceleration
T3 = (F_n - f_e) / a; // (s) Decel Time = difference in feedrate over acceleration
N1 = ceil(T1 * (FTM_FS)); // Accel datapoints based on Hz frequency N1 = ceil(T1 * (FTM_FS)); // Accel datapoints based on Hz frequency
N2 = ceil(T2 * (FTM_FS)); // Coast N2 = ceil(T2 * (FTM_FS)); // Coast
@ -536,7 +537,7 @@ void FxdTiCtrl::loadBlockData(block_t * const current_block) {
} }
// Generate data points of the trajectory. // Generate data points of the trajectory.
void FxdTiCtrl::makeVector() { void FTMotion::makeVector() {
float accel_k = 0.0f; // (mm/s^2) Acceleration K factor float accel_k = 0.0f; // (mm/s^2) Acceleration K factor
float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block float tau = (makeVector_idx + 1) * (FTM_TS); // (s) Time since start of block
float dist = 0.0f; // (mm) Distance traveled float dist = 0.0f; // (mm) Distance traveled
@ -653,7 +654,7 @@ void FxdTiCtrl::makeVector() {
} }
// Interpolates single data point to stepper commands. // Interpolates single data point to stepper commands.
void FxdTiCtrl::convertToSteps(const uint32_t idx) { void FTMotion::convertToSteps(const uint32_t idx) {
xyze_long_t err_P = { 0 }; xyze_long_t err_P = { 0 };
//#define STEPS_ROUNDING //#define STEPS_ROUNDING

View file

@ -64,12 +64,13 @@ typedef struct FTConfig {
#endif #endif
} ft_config_t; } ft_config_t;
class FxdTiCtrl { class FTMotion {
public: public:
// Public variables // Public variables
static ft_config_t cfg; static ft_config_t cfg;
static bool busy;
static void set_defaults() { static void set_defaults() {
cfg.mode = FTM_DEFAULT_MODE; cfg.mode = FTM_DEFAULT_MODE;
@ -77,8 +78,8 @@ class FxdTiCtrl {
TERN_(HAS_X_AXIS, cfg.baseFreq[X_AXIS] = FTM_SHAPING_DEFAULT_X_FREQ); TERN_(HAS_X_AXIS, cfg.baseFreq[X_AXIS] = FTM_SHAPING_DEFAULT_X_FREQ);
TERN_(HAS_Y_AXIS, cfg.baseFreq[Y_AXIS] = FTM_SHAPING_DEFAULT_Y_FREQ); TERN_(HAS_Y_AXIS, cfg.baseFreq[Y_AXIS] = FTM_SHAPING_DEFAULT_Y_FREQ);
cfg.zeta = FTM_SHAPING_ZETA; cfg.zeta = FTM_SHAPING_ZETA; // Damping factor
cfg.vtol = FTM_SHAPING_V_TOL; cfg.vtol = FTM_SHAPING_V_TOL; // Vibration Level
#if HAS_DYNAMIC_FREQ #if HAS_DYNAMIC_FREQ
cfg.dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE; cfg.dynFreqMode = FTM_DEFAULT_DYNFREQ_MODE;
@ -114,7 +115,6 @@ class FxdTiCtrl {
static void runoutBlock(); // Move any free data points to the stepper buffer even if a full batch isn't ready. static void runoutBlock(); // Move any free data points to the stepper buffer even if a full batch isn't ready.
static void loop(); // Controller main, to be invoked from non-isr task. static void loop(); // Controller main, to be invoked from non-isr task.
#if HAS_X_AXIS #if HAS_X_AXIS
// Refresh the gains used by shaping functions. // Refresh the gains used by shaping functions.
// To be called on init or mode or zeta change. // To be called on init or mode or zeta change.
@ -168,6 +168,7 @@ class FxdTiCtrl {
static hal_timer_t nextStepTicks; static hal_timer_t nextStepTicks;
// Shaping variables.
#if HAS_X_AXIS #if HAS_X_AXIS
typedef struct AxisShaping { typedef struct AxisShaping {
@ -202,10 +203,10 @@ class FxdTiCtrl {
// Private methods // Private methods
static uint32_t stepperCmdBuffItems(); static uint32_t stepperCmdBuffItems();
static void loadBlockData(block_t * const current_block); static void loadBlockData(block_t *const current_block);
static void makeVector(); static void makeVector();
static void convertToSteps(const uint32_t idx); static void convertToSteps(const uint32_t idx);
}; // class fxdTiCtrl }; // class FTMotion
extern FxdTiCtrl fxdTiCtrl; extern FTMotion ftMotion;

View file

@ -56,15 +56,9 @@ typedef struct XYZEval<stepDirState_t> xyze_stepDir_t;
enum { enum {
LIST_N(DOUBLE(LOGICAL_AXES), LIST_N(DOUBLE(LOGICAL_AXES),
FT_BIT_DIR_E, FT_BIT_STEP_E, FT_BIT_DIR_E, FT_BIT_STEP_E,
FT_BIT_DIR_X, FT_BIT_STEP_X, FT_BIT_DIR_X, FT_BIT_STEP_X, FT_BIT_DIR_Y, FT_BIT_STEP_Y, FT_BIT_DIR_Z, FT_BIT_STEP_Z,
FT_BIT_DIR_Y, FT_BIT_STEP_Y, FT_BIT_DIR_I, FT_BIT_STEP_I, FT_BIT_DIR_J, FT_BIT_STEP_J, FT_BIT_DIR_K, FT_BIT_STEP_K,
FT_BIT_DIR_Z, FT_BIT_STEP_Z, FT_BIT_DIR_U, FT_BIT_STEP_U, FT_BIT_DIR_V, FT_BIT_STEP_V, FT_BIT_DIR_W, FT_BIT_STEP_W
FT_BIT_DIR_I, FT_BIT_STEP_I,
FT_BIT_DIR_J, FT_BIT_STEP_J,
FT_BIT_DIR_K, FT_BIT_STEP_K,
FT_BIT_DIR_U, FT_BIT_STEP_U,
FT_BIT_DIR_V, FT_BIT_STEP_V,
FT_BIT_DIR_W, FT_BIT_STEP_W
), ),
FT_BIT_COUNT FT_BIT_COUNT
}; };

View file

@ -2100,12 +2100,12 @@ void prepare_line_to_destination() {
struct OnExit { struct OnExit {
ftMotionMode_t oldmm; ftMotionMode_t oldmm;
OnExit() { OnExit() {
oldmm = fxdTiCtrl.cfg.mode; oldmm = ftMotion.cfg.mode;
fxdTiCtrl.cfg.mode = ftMotionMode_DISABLED; ftMotion.cfg.mode = ftMotionMode_DISABLED;
} }
~OnExit() { ~OnExit() {
fxdTiCtrl.cfg.mode = oldmm; ftMotion.cfg.mode = oldmm;
fxdTiCtrl.init(); ftMotion.init();
} }
} on_exit; } on_exit;
#endif #endif

View file

@ -229,10 +229,6 @@ float Planner::previous_nominal_speed;
int32_t Planner::xy_freq_min_interval_us = LROUND(1000000.0f / (XY_FREQUENCY_LIMIT)); int32_t Planner::xy_freq_min_interval_us = LROUND(1000000.0f / (XY_FREQUENCY_LIMIT));
#endif #endif
#if ENABLED(FT_MOTION)
bool Planner::fxdTiCtrl_busy = false;
#endif
#if ENABLED(LIN_ADVANCE) #if ENABLED(LIN_ADVANCE)
float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load() float Planner::extruder_advance_K[DISTINCT_E]; // Initialized by settings.load()
#endif #endif
@ -1692,7 +1688,7 @@ void Planner::quick_stop() {
// Restart the block delay for the first movement - As the queue was // Restart the block delay for the first movement - As the queue was
// forced to empty, there's no risk the ISR will touch this. // forced to empty, there's no risk the ISR will touch this.
delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE;
TERN_(HAS_WIRED_LCD, clear_block_buffer_runtime()); // Clear the accumulated runtime TERN_(HAS_WIRED_LCD, clear_block_buffer_runtime()); // Clear the accumulated runtime
@ -1738,7 +1734,7 @@ bool Planner::busy() {
return (has_blocks_queued() || cleaning_buffer_counter return (has_blocks_queued() || cleaning_buffer_counter
|| TERN0(EXTERNAL_CLOSED_LOOP_CONTROLLER, CLOSED_LOOP_WAITING()) || TERN0(EXTERNAL_CLOSED_LOOP_CONTROLLER, CLOSED_LOOP_WAITING())
|| TERN0(HAS_ZV_SHAPING, stepper.input_shaping_busy()) || TERN0(HAS_ZV_SHAPING, stepper.input_shaping_busy())
|| TERN0(FT_MOTION, fxdTiCtrl_busy) || TERN0(FT_MOTION, ftMotion.busy)
); );
} }
@ -1851,7 +1847,7 @@ bool Planner::_buffer_steps(const xyze_long_t &target
// As there are no queued movements, the Stepper ISR will not touch this // As there are no queued movements, the Stepper ISR will not touch this
// variable, so there is no risk setting this here (but it MUST be done // variable, so there is no risk setting this here (but it MUST be done
// before the following line!!) // before the following line!!)
delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE;
} }
// Move buffer head // Move buffer head
@ -2924,7 +2920,7 @@ void Planner::buffer_sync_block(const BlockFlagBit sync_flag/*=BLOCK_BIT_SYNC_PO
// As there are no queued movements, the Stepper ISR will not touch this // As there are no queued movements, the Stepper ISR will not touch this
// variable, so there is no risk setting this here (but it MUST be done // variable, so there is no risk setting this here (but it MUST be done
// before the following line!!) // before the following line!!)
delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE;
} }
block_buffer_head = next_buffer_head; block_buffer_head = next_buffer_head;
@ -3217,7 +3213,7 @@ bool Planner::buffer_line(const xyze_pos_t &cart, const_feedRate_t fr_mm_s
// As there are no queued movements, the Stepper ISR will not touch this // As there are no queued movements, the Stepper ISR will not touch this
// variable, so there is no risk setting this here (but it MUST be done // variable, so there is no risk setting this here (but it MUST be done
// before the following line!!) // before the following line!!)
delay_before_delivering = TERN_(FT_MOTION, fxdTiCtrl.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE; delay_before_delivering = TERN_(FT_MOTION, ftMotion.cfg.mode ? BLOCK_DELAY_NONE :) BLOCK_DELAY_FOR_1ST_MOVE;
} }
// Move buffer head // Move buffer head

View file

@ -529,10 +529,6 @@ class Planner {
} }
#endif #endif
#if ENABLED(FT_MOTION)
static bool fxdTiCtrl_busy;
#endif
private: private:
/** /**

View file

@ -612,7 +612,7 @@ typedef struct SettingsDataStruct {
// Fixed-Time Motion // Fixed-Time Motion
// //
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
ft_config_t fxdTiCtrl_cfg; // M493 ft_config_t ftMotion_cfg; // M493
#endif #endif
// //
@ -1711,8 +1711,8 @@ void MarlinSettings::postprocess() {
// Fixed-Time Motion // Fixed-Time Motion
// //
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
_FIELD_TEST(fxdTiCtrl_cfg); _FIELD_TEST(ftMotion_cfg);
EEPROM_WRITE(fxdTiCtrl.cfg); EEPROM_WRITE(ftMotion.cfg);
#endif #endif
// //
@ -2785,8 +2785,8 @@ void MarlinSettings::postprocess() {
// Fixed-Time Motion // Fixed-Time Motion
// //
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
_FIELD_TEST(fxdTiCtrl_cfg); _FIELD_TEST(ftMotion_cfg);
EEPROM_READ(fxdTiCtrl.cfg); EEPROM_READ(ftMotion.cfg);
#endif #endif
// //
@ -3614,7 +3614,7 @@ void MarlinSettings::reset() {
// //
// Fixed-Time Motion // Fixed-Time Motion
// //
TERN_(FT_MOTION, fxdTiCtrl.set_defaults()); TERN_(FT_MOTION, ftMotion.set_defaults());
// //
// Nonlinear Extrusion // Nonlinear Extrusion

View file

@ -1492,11 +1492,14 @@ void Stepper::isr() {
uint8_t max_loops = 10; uint8_t max_loops = 10;
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
static bool fxdTiCtrl_stepCmdRdy = false; // Indicates a step command was loaded from the static bool ftMotion_stepCmdRdy = false; // Indicates a step command was loaded from the
// buffers and is ready to be output. // buffers and is ready to be output.
static bool fxdTiCtrl_applyDir = false; // Indicates the DIR output should be set. static bool ftMotion_applyDir = false; // Indicates the DIR output should be set.
static ft_command_t fxdTiCtrl_stepCmd = 0U; // Storage for the step command to be output. static ft_command_t ftMotion_stepCmd = 0U; // Storage for the step command to be output.
static uint32_t fxdTiCtrl_nextAuxISR = 0U; // Storage for the next ISR of the auxilliary tasks. static uint32_t ftMotion_nextAuxISR = 0U; // Storage for the next ISR of the auxilliary tasks.
const bool using_ftMotion = ftMotion.cfg.mode;
#else
constexpr bool using_ftMotion = false;
#endif #endif
// We need this variable here to be able to use it in the following loop // We need this variable here to be able to use it in the following loop
@ -1509,64 +1512,58 @@ void Stepper::isr() {
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
// NOTE STEPPER_TIMER_RATE is equal to 2000000, not what VSCode shows if (using_ftMotion) {
const bool using_fxtictrl = fxdTiCtrl.cfg.mode;
if (using_fxtictrl) {
if (!nextMainISR) { if (!nextMainISR) {
if (abort_current_block) { if (abort_current_block) {
fxdTiCtrl_stepCmdRdy = false; // If a command was ready, cancel it. ftMotion_stepCmdRdy = false; // If a command was ready, cancel it.
fxdTiCtrl.sts_stepperBusy = false; // Set busy false to allow a reset. ftMotion.sts_stepperBusy = false; // Set busy false to allow a reset.
nextMainISR = 0.01f * (STEPPER_TIMER_RATE); // Come back in 10 msec. nextMainISR = 0.01f * (STEPPER_TIMER_RATE); // Come back in 10 msec.
} }
else { // !(abort_current_block) else { // !(abort_current_block)
if (fxdTiCtrl_stepCmdRdy) { if (ftMotion_stepCmdRdy) {
fxdTiCtrl_stepper(fxdTiCtrl_applyDir, fxdTiCtrl_stepCmd); ftMotion_stepper(ftMotion_applyDir, ftMotion_stepCmd);
fxdTiCtrl_stepCmdRdy = false; ftMotion_stepCmdRdy = false;
} }
// Check if there is data in the buffers. // Check if there is data in the buffers.
if (fxdTiCtrl.stepperCmdBuff_produceIdx != fxdTiCtrl.stepperCmdBuff_consumeIdx) { if (ftMotion.stepperCmdBuff_produceIdx != ftMotion.stepperCmdBuff_consumeIdx) {
fxdTiCtrl.sts_stepperBusy = true; ftMotion.sts_stepperBusy = true;
// "Pop" one command from the command buffer. // "Pop" one command from the command buffer.
fxdTiCtrl_stepCmd = fxdTiCtrl.stepperCmdBuff[fxdTiCtrl.stepperCmdBuff_consumeIdx]; ftMotion_stepCmd = ftMotion.stepperCmdBuff[ftMotion.stepperCmdBuff_consumeIdx];
const uint8_t dir_index = fxdTiCtrl.stepperCmdBuff_consumeIdx >> 3, const uint8_t dir_index = ftMotion.stepperCmdBuff_consumeIdx >> 3,
dir_bit = fxdTiCtrl.stepperCmdBuff_consumeIdx & 0x7; dir_bit = ftMotion.stepperCmdBuff_consumeIdx & 0x7;
fxdTiCtrl_applyDir = TEST(fxdTiCtrl.stepperCmdBuff_ApplyDir[dir_index], dir_bit); ftMotion_applyDir = TEST(ftMotion.stepperCmdBuff_ApplyDir[dir_index], dir_bit);
nextMainISR = fxdTiCtrl.stepperCmdBuff_StepRelativeTi[fxdTiCtrl.stepperCmdBuff_consumeIdx]; nextMainISR = ftMotion.stepperCmdBuff_StepRelativeTi[ftMotion.stepperCmdBuff_consumeIdx];
fxdTiCtrl_stepCmdRdy = true; ftMotion_stepCmdRdy = true;
if (++fxdTiCtrl.stepperCmdBuff_consumeIdx == (FTM_STEPPERCMD_BUFF_SIZE)) if (++ftMotion.stepperCmdBuff_consumeIdx == (FTM_STEPPERCMD_BUFF_SIZE))
fxdTiCtrl.stepperCmdBuff_consumeIdx = 0; ftMotion.stepperCmdBuff_consumeIdx = 0;
} }
else { // Buffer empty. else { // Buffer empty.
fxdTiCtrl.sts_stepperBusy = false; ftMotion.sts_stepperBusy = false;
nextMainISR = 0.01f * (STEPPER_TIMER_RATE); // Come back in 10 msec. nextMainISR = 0.01f * (STEPPER_TIMER_RATE); // Come back in 10 msec.
} }
} // !(abort_current_block) } // !(abort_current_block)
} // if (!nextMainISR) } // if (!nextMainISR)
// Define 2.5 msec task for auxilliary functions. // Define 2.5 msec task for auxiliary functions.
if (!fxdTiCtrl_nextAuxISR) { if (!ftMotion_nextAuxISR) {
endstops.update(); endstops.update();
TERN_(BABYSTEPPING, if (babystep.has_steps()) babystepping_isr()); TERN_(BABYSTEPPING, if (babystep.has_steps()) babystepping_isr());
fxdTiCtrl_refreshAxisDidMove(); ftMotion_refreshAxisDidMove();
fxdTiCtrl_nextAuxISR = 0.0025f * (STEPPER_TIMER_RATE); ftMotion_nextAuxISR = 0.0025f * (STEPPER_TIMER_RATE);
} }
interval = _MIN(nextMainISR, fxdTiCtrl_nextAuxISR); interval = _MIN(nextMainISR, ftMotion_nextAuxISR);
nextMainISR -= interval; nextMainISR -= interval;
fxdTiCtrl_nextAuxISR -= interval; ftMotion_nextAuxISR -= interval;
} }
#else
constexpr bool using_fxtictrl = false;
#endif #endif
if (!using_fxtictrl) { if (!using_ftMotion) {
TERN_(HAS_ZV_SHAPING, shaping_isr()); // Do Shaper stepping, if needed TERN_(HAS_ZV_SHAPING, shaping_isr()); // Do Shaper stepping, if needed
@ -3436,12 +3433,8 @@ void Stepper::report_a_position(const xyz_long_t &pos) {
TERN(SAYS_A, PSTR(STR_COUNT_A), PSTR(STR_COUNT_X)), pos.x, TERN(SAYS_A, PSTR(STR_COUNT_A), PSTR(STR_COUNT_X)), pos.x,
TERN(SAYS_B, PSTR("B:"), SP_Y_LBL), pos.y, TERN(SAYS_B, PSTR("B:"), SP_Y_LBL), pos.y,
TERN(SAYS_C, PSTR("C:"), SP_Z_LBL), pos.z, TERN(SAYS_C, PSTR("C:"), SP_Z_LBL), pos.z,
SP_I_LBL, pos.i, SP_I_LBL, pos.i, SP_J_LBL, pos.j, SP_K_LBL, pos.k,
SP_J_LBL, pos.j, SP_U_LBL, pos.u, SP_V_LBL, pos.v, SP_W_LBL, pos.w
SP_K_LBL, pos.k,
SP_U_LBL, pos.u,
SP_V_LBL, pos.v,
SP_W_LBL, pos.w
) )
); );
#endif #endif
@ -3466,7 +3459,7 @@ void Stepper::report_positions() {
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
// Set stepper I/O for fixed time controller. // Set stepper I/O for fixed time controller.
void Stepper::fxdTiCtrl_stepper(const bool applyDir, const ft_command_t command) { void Stepper::ftMotion_stepper(const bool applyDir, const ft_command_t command) {
USING_TIMED_PULSE(); USING_TIMED_PULSE();
@ -3558,13 +3551,13 @@ void Stepper::report_positions() {
if (axis_step.w) W_APPLY_STEP(!STEP_STATE_W, false) if (axis_step.w) W_APPLY_STEP(!STEP_STATE_W, false)
); );
} // Stepper::fxdTiCtrl_stepper } // Stepper::ftMotion_stepper
void Stepper::fxdTiCtrl_BlockQueueUpdate() { void Stepper::ftMotion_BlockQueueUpdate() {
if (current_block) { if (current_block) {
// If the current block is not done processing, return right away // If the current block is not done processing, return right away
if (!fxdTiCtrl.getBlockProcDn()) return; if (!ftMotion.getBlockProcDn()) return;
axis_did_move.reset(); axis_did_move.reset();
current_block = nullptr; current_block = nullptr;
@ -3591,21 +3584,21 @@ void Stepper::report_positions() {
// update it here, even though it will may be out of sync with step commands // update it here, even though it will may be out of sync with step commands
last_direction_bits = current_block->direction_bits; last_direction_bits = current_block->direction_bits;
fxdTiCtrl.startBlockProc(current_block); ftMotion.startBlockProc(current_block);
} }
else { else {
fxdTiCtrl.runoutBlock(); ftMotion.runoutBlock();
return; // No queued blocks return; // No queued blocks
} }
} // if (!current_block) } // if (!current_block)
} // Stepper::fxdTiCtrl_BlockQueueUpdate() } // Stepper::ftMotion_BlockQueueUpdate()
// Debounces the axis move indication to account for potential // Debounces the axis move indication to account for potential
// delay between the block information and the stepper commands // delay between the block information and the stepper commands
void Stepper::fxdTiCtrl_refreshAxisDidMove() { void Stepper::ftMotion_refreshAxisDidMove() {
// Set the debounce time in seconds. // Set the debounce time in seconds.
#define AXIS_DID_MOVE_DEB 5 // TODO: The debounce time should be calculated if possible, #define AXIS_DID_MOVE_DEB 5 // TODO: The debounce time should be calculated if possible,

View file

@ -294,7 +294,7 @@ constexpr ena_mask_t enable_overlap[] = {
// //
class Stepper { class Stepper {
friend class Max7219; friend class Max7219;
friend class FxdTiCtrl; friend class FTMotion;
friend void stepperTask(void *); friend void stepperTask(void *);
public: public:
@ -535,7 +535,7 @@ class Stepper {
if (current_block->is_page()) page_manager.free_page(current_block->page_idx); if (current_block->is_page()) page_manager.free_page(current_block->page_idx);
#endif #endif
current_block = nullptr; current_block = nullptr;
axis_did_move = 0; axis_did_move.reset();
planner.release_current_block(); planner.release_current_block();
TERN_(LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER); TERN_(LIN_ADVANCE, la_interval = nextAdvanceISR = LA_ADV_NEVER);
} }
@ -654,7 +654,7 @@ class Stepper {
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
// Manage the planner // Manage the planner
static void fxdTiCtrl_BlockQueueUpdate(); static void ftMotion_BlockQueueUpdate();
#endif #endif
#if HAS_ZV_SHAPING #if HAS_ZV_SHAPING
@ -693,8 +693,8 @@ class Stepper {
#endif #endif
#if ENABLED(FT_MOTION) #if ENABLED(FT_MOTION)
static void fxdTiCtrl_stepper(const bool applyDir, const ft_command_t command); static void ftMotion_stepper(const bool applyDir, const ft_command_t command);
static void fxdTiCtrl_refreshAxisDidMove(); static void ftMotion_refreshAxisDidMove();
#endif #endif
}; };