diff --git a/README.md b/README.md
index 98b01ed..ad17f93 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
## grblHAL ##
-Latest build date is 20250103, see the [changelog](changelog.md) for details.
+Latest build date is 20250107, see the [changelog](changelog.md) for details.
> [!NOTE]
> A settings reset will be performed on an update of builds prior to 20241208. Backup and restore of settings is recommended.
@@ -93,4 +93,4 @@ G/M-codes not supported by [legacy Grbl](https://github.com/gnea/grbl/wiki) are
Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes.
---
-20250103
+20250107
diff --git a/changelog.md b/changelog.md
index b02c005..4afe309 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,27 @@
## grblHAL changelog
+20250107
+
+Core:
+
+* Added setting `$539` for spindle spin down delay. Ref. issue [#651](https://github.com/grblHAL/core/issues/651).
+
+Drivers:
+
+* RP2040, STM32F4xx and STM32F7xx: increased reset delay for WizNet ethernet modules.
+
+* iMXRT1062, STM32F4xx and STM32F7xx: fixed regression affecting step injection, used when stepper spindle or plasma THC is enabled.
+
+* STM32F7xx: removed code left over from copy/paste update. Ref. issue [#20](https://github.com/grblHAL/STM32F7xx/issues/20).
+
+Plugins:
+
+* Spindle, stepper: improved settings changes handling. Added a bit of documentation. Ref. issue [#30](https://github.com/grblHAL/Plugins_spindle/issues/30).
+
+* SD card: added inbuilt macro `G65P4` for getting the [current machine state](https://github.com/grblHAL/core/wiki/Expressions-and-flow-control#inbuilt-g65-macros).
+
+---
+
20250104
Core:
diff --git a/config.h b/config.h
index 6fc7e7f..9487742 100644
--- a/config.h
+++ b/config.h
@@ -1154,6 +1154,14 @@ Default value is 0, meaning spindle sync is disabled
#endif
///@}
+/*! @name $539 - Setting_SpindleOffDelay
+*/
+///@{
+#if !defined DEFAULT_SPINDLE_OFF_DELAY || defined __DOXYGEN__
+#define DEFAULT_SPINDLE_OFF_DELAY 0 // milliseconds: 0 or 500 - 20000
+#endif
+///@}
+
// Closed loop spindle settings (Group_Spindle_ClosedLoop)
// $9 - Setting_SpindlePWMOptions
diff --git a/grbl.h b/grbl.h
index 8b8c365..49c4028 100644
--- a/grbl.h
+++ b/grbl.h
@@ -42,7 +42,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
-#define GRBL_BUILD 20250104
+#define GRBL_BUILD 20250107
#define GRBL_URL "https://github.com/grblHAL"
diff --git a/machine_limits.c b/machine_limits.c
index 82b31a3..4594bad 100644
--- a/machine_limits.c
+++ b/machine_limits.c
@@ -3,7 +3,7 @@
Part of grblHAL
- Copyright (c) 2017-2024 Terje Io
+ Copyright (c) 2017-2025 Terje Io
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -656,12 +656,8 @@ static float get_homing_rate (axes_signals_t cycle, homing_mode_t mode)
{
uint_fast8_t idx = 0;
- while(cycle.mask) {
- if(cycle.mask & 1)
- break;
- idx++;
- cycle.mask >>= 1;
- }
+ if(settings.homing.flags.per_axis_feedrates)
+ idx = ffs(cycle.mask) - 1;
return mode == HomingMode_Locate ? settings.axis[idx].homing_feed_rate : settings.axis[idx].homing_seek_rate;
}
diff --git a/settings.c b/settings.c
index c5f89c1..472283d 100644
--- a/settings.c
+++ b/settings.c
@@ -161,6 +161,7 @@ PROGMEM const settings_t defaults = {
.spindle.ref_id = DEFAULT_SPINDLE,
.spindle.on_delay = DEFAULT_SPINDLE_ON_DELAY,
+ .spindle.off_delay = DEFAULT_SPINDLE_OFF_DELAY,
.spindle.at_speed_tolerance = DEFAULT_SPINDLE_AT_SPEED_TOLERANCE,
.spindle.encoder_spindle = DEFAULT_SPINDLE,
.spindle.ppr = DEFAULT_SPINDLE_PPR,
@@ -1147,6 +1148,10 @@ static status_code_t set_float (setting_id_t setting, float value)
settings.spindle.on_delay = (uint16_t)(value * 1000.0f);
break;
+ case Setting_SpindleOffDelay:
+ settings.spindle.off_delay = (uint16_t)(value * 1000.0f);
+ break;
+
case Setting_CoolantOnDelay:
settings.coolant.on_delay = (uint16_t)(value * 1000.0f);
break;
@@ -1332,6 +1337,10 @@ static float get_float (setting_id_t setting)
value = (float)settings.spindle.on_delay / 1000.0f;
break;
+ case Setting_SpindleOffDelay:
+ value = (float)settings.spindle.off_delay / 1000.0f;
+ break;
+
case Setting_CoolantOnDelay:
value = (float)settings.coolant.on_delay / 1000.0f;
break;
@@ -1807,6 +1816,7 @@ static bool is_setting_available (const setting_detail_t *setting)
break;
case Setting_SpindleOnDelay:
+ case Setting_SpindleOffDelay:
available = spindle_get_count();
break;
@@ -2063,6 +2073,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
#if N_AXIS > 3
{ Setting_RotaryWrap, Group_Stepper, "Fast rotary go to G28", NULL, Format_Bitfield, rotary_axes, NULL, NULL, Setting_IsExtendedFn, set_rotary_wrap_axes, get_int, NULL },
#endif
+ { Setting_SpindleOffDelay, Group_Spindle, "Spindle off delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } },
{ Setting_FSOptions, Group_General, "File systems options", NULL, Format_Bitfield, fs_options, NULL, NULL, Setting_IsExtended, &settings.fs_options.mask, NULL, is_setting_available },
{ Setting_HomePinsInvertMask, Group_Limits, "Invert home inputs", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsExtended, &settings.home_invert.mask, NULL, is_setting_available },
{ Setting_CoolantOnDelay, Group_Coolant, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtendedFn, set_float, get_float, is_setting_available, { .allow_null = On } }
@@ -2237,7 +2248,7 @@ PROGMEM static const setting_descr_t setting_descr[] = {
{ Setting_DoorCoolantOnDelay, "Delay to allow coolant to restart after safety door is opened." },
#endif
{ Setting_SpindleOnDelay, "Delay to allow spindle to spin up. 0 or 0.5 - 20s\\n"
- "If spindle supports ""at speed"" functionality it is the time to wait before alarm 14 is raised."
+ "If spindle supports \"at speed\" functionality it is the time to wait before alarm 14 is raised."
},
{ Setting_SpindleType, "Spindle selected on startup." },
{ Setting_PlannerBlocks, "Number of blocks in the planner buffer." },
@@ -2250,6 +2261,9 @@ PROGMEM static const setting_descr_t setting_descr[] = {
#if NGC_EXPRESSIONS_ENABLE
{ Setting_NGCDebugOut, "Example: (debug, metric mode: #<_metric>, coord system: #5220)" },
#endif
+ { Setting_SpindleOffDelay, "Delay to allow spindle to spin down. 0 or 0.5 - 20s\\n"
+ "If spindle supports \"at speed\" functionality it is the time to wait before alarm 14 is raised."
+ },
{ Setting_EncoderSpindle, "Specifies which spindle has the encoder attached." },
#if N_AXIS > 3
{ Setting_RotaryWrap, "Perform fast move to angle stored in G28 position.\\n"
diff --git a/settings.h b/settings.h
index 4c5f703..409bdb8 100644
--- a/settings.h
+++ b/settings.h
@@ -265,7 +265,7 @@ typedef enum {
Setting_LaserCoolantOkPort = 391,
Setting_DoorSpindleOnDelay = 392,
Setting_DoorCoolantOnDelay = 393,
- Setting_SpindleOnDelay = 394, // made available if safety door input not provided
+ Setting_SpindleOnDelay = 394,
Setting_SpindleType = 395,
Setting_WebUiTimeout = 396,
Setting_WebUiAutoReportInterval = 397,
@@ -373,6 +373,7 @@ typedef enum {
Setting_RGB_StripLengt0 = 536,
Setting_RGB_StripLengt1 = 537,
Setting_RotaryWrap = 538,
+ Setting_SpindleOffDelay = 539,
Setting_Panel_SpindleSpeed = 540, // NOTE: Reserving settings values 540 to 579 for panel settings.
Setting_Panel_ModbusAddress = 541,
diff --git a/spindle_control.c b/spindle_control.c
index da08a88..d734ea0 100644
--- a/spindle_control.c
+++ b/spindle_control.c
@@ -637,7 +637,7 @@ for it to reach the speed and raise an alarm if the speed is not reached within
bool spindle_set_state_synced (spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
{
// Empty planner buffer to ensure spindle is set when programmed.
- return protocol_buffer_synchronize() && spindle_set_state_wait(spindle, state, rpm, settings.spindle.on_delay, DelayMode_Dwell);
+ return protocol_buffer_synchronize() && spindle_set_state_wait(spindle, state, rpm, state.on ? settings.spindle.on_delay : settings.spindle.off_delay, DelayMode_Dwell);
}
/*! \brief Restore spindle running state with direction, enable, spindle RPM and appropriate delay.
diff --git a/spindle_control.h b/spindle_control.h
index c8c5808..40e3ffe 100644
--- a/spindle_control.h
+++ b/spindle_control.h
@@ -225,6 +225,7 @@ typedef struct {
uint8_t encoder_spindle;
uint16_t ppr; //!< Spindle encoder pulses per revolution (PPR).
uint16_t on_delay;
+ uint16_t off_delay;
float at_speed_tolerance; //!< Tolerance in percent of programmed speed.
} spindle_settings_t;