Changed spindle handling to allow dynamic spindle registration and support for multiple spindles selectable at run-time.

See the changelog for more info.
This commit is contained in:
Terje Io
2022-03-25 23:01:56 +01:00
parent 31f6a4bf04
commit dae7d56ab5
19 changed files with 448 additions and 200 deletions

View File

@@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa
---
Latest build date is 20220210, see the [changelog](changelog.md) for details.
Latest build date is 20220325, see the [changelog](changelog.md) for details.
__NOTE:__ A settings reset will be performed on an update for versions earlier than 20211122. Backup and restore of settings is recommended.
__IMPORTANT!__ A new setting has been introduced for ganged axes motors in version 20211121.
I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured.

View File

@@ -1,5 +1,27 @@
## grblHAL changelog
20220325:
Core:
* Changed spindle handling to allow dynamic spindle registration and support for multiple spindles selectable at run-time.
If more than one spindle is to be made available [grbl/config.h](https://github.com/grblHAL/core/blob/master/config.h) has to be edited and the symbol `N_SPINDLE` has to be increased from the default value of 1 to the number of spindles to allow \(currently max 8\).
When more than one spindle is registered setting `$395` becomes available for specifying the spindle to enable at startup. Use `$$=395` to output a list of available spindles and the corresponding spindle id to use for configuration.
__NOTE:__ Using `$32` for switching between a PWM spindle and a VFD spindle is no longer supported, either use `$395` or `M104P0` to select the PWM spindle, `M104P1` to select the configured VFD spindle.
Note that laser mode \(`$32=1`\) will be disabled if the active spindle is not a PWM spindle.
__NOTE:__ the change is not backwards compatible with current 3rd party drivers, these has to be updated to match the changed core.
Plugins:
* The PPI and spindle plugins has been updated for the new spindle handling.
Drivers:
* All: updated for the new spindle handling.
__NOTE:__ I have only done limited testing of the changes, please report any problems!
---
20220315:
Drivers:

View File

@@ -40,6 +40,12 @@ If more than 3 axes are configured a compliant driver and map file is needed.
#define N_AXIS 3 // Number of axes
#endif
#ifndef N_SPINDLE
/*! Defines number of spindles supported - minimum 1, maximum 8
*/
#define N_SPINDLE 1
#endif
#ifndef COMPATIBILITY_LEVEL
/*! Define compatibility level with the grbl 1.1 protocol.
@@ -110,12 +116,6 @@ __NOTE:__ these definitions are only referenced in this file. Do __NOT__ change!
// #define DEBUG // Uncomment to enable. Default disabled.
// #define DEBUGOUT 0 // Uncomment to claim serial port with given instance number and add HAL entry point for debug output.
// If spindle RPM is set by high-level commands to a spindle controller (eg. via Modbus) or the driver supports closed loop
// spindle RPM control either uncomment the #define SPINDLE_RPM_CONTROLLED below or add SPINDLE_RPM_CONTROLLED as predefined symbol
// on the compiler command line. This will send spindle speed as a RPM value instead of a PWM value to the driver.
//#define SPINDLE_RPM_CONTROLLED
// Some status report data isn't necessary for realtime, only intermittently, because the values don't
// change often. The following macros configures how many times a status report needs to be called before
// the associated data is refreshed and included in the status report. However, if one of these value

View File

@@ -84,7 +84,7 @@ typedef bool (*on_probe_fixture_ptr)(tool_data_t *tool, bool at_g59_3, bool on);
typedef bool (*on_probe_start_ptr)(axes_signals_t axes, float *target, plan_line_data_t *pl_data);
typedef void (*on_probe_completed_ptr)(void);
typedef void (*on_toolchange_ack_ptr)(void);
typedef bool (*on_spindle_select_ptr)(uint_fast8_t spindle_id);
typedef bool (*on_spindle_select_ptr)(spindle_id_t spindle_id);
typedef status_code_t (*on_unknown_sys_command_ptr)(sys_state_t state, char *line); // return Status_Unhandled.
typedef status_code_t (*on_user_command_ptr)(char *line);
typedef sys_commands_t *(*on_get_commands_ptr)(void);

14
gcode.c
View File

@@ -919,7 +919,7 @@ status_code_t gc_execute_block(char *block)
break;
*/
case 96: case 97:
if(sys.mode == Mode_Lathe && hal.driver_cap.variable_spindle) {
if(sys.mode == Mode_Lathe && hal.spindle.cap.variable) {
word_bit.modal_group.G14 = On;
gc_block.modal.spindle_rpm_mode = (spindle_rpm_mode_t)((int_value - 96) ^ 1);
} else
@@ -1405,10 +1405,10 @@ status_code_t gc_execute_block(char *block)
FAIL(Status_GcodeValueWordMissing);
// see below!! gc_block.values.s *= (gc_block.modal.units_imperial ? MM_PER_INCH * 12.0f : 1000.0f); // convert surface speed to mm/min
if (gc_block.words.d) {
gc_state.spindle.css.max_rpm = min(gc_block.values.d, settings.spindle.rpm_max);
gc_state.spindle.css.max_rpm = min(gc_block.values.d, hal.spindle.rpm_max);
gc_block.words.d = Off;
} else
gc_state.spindle.css.max_rpm = settings.spindle.rpm_max;
gc_state.spindle.css.max_rpm = hal.spindle.rpm_max;
} else if(gc_state.modal.spindle_rpm_mode == SpindleSpeedMode_CSS)
gc_state.spindle.rpm = sys.spindle_rpm; // Is it correct to restore latest spindle RPM here?
gc_state.modal.spindle_rpm_mode = gc_block.modal.spindle_rpm_mode;
@@ -2005,7 +2005,7 @@ status_code_t gc_execute_block(char *block)
(gc_block.words.l && (gc_taper_type)gc_block.values.l > Taper_Both))
FAIL(Status_GcodeValueOutOfRange);
if(gc_state.spindle.rpm < settings.spindle.rpm_min || gc_state.spindle.rpm > settings.spindle.rpm_max)
if(gc_state.spindle.rpm < hal.spindle.rpm_min || gc_state.spindle.rpm > hal.spindle.rpm_max)
FAIL(Status_GcodeRPMOutOfRange);
if(gc_block.modal.motion != gc_state.modal.motion) {
@@ -2491,7 +2491,7 @@ status_code_t gc_execute_block(char *block)
gc_parser_flags.spindle_force_sync = On;
}
gc_state.is_rpm_rate_adjusted = gc_state.modal.spindle.ccw && !gc_parser_flags.laser_disable && hal.driver_cap.variable_spindle;
gc_state.is_rpm_rate_adjusted = gc_state.modal.spindle.ccw && !gc_parser_flags.laser_disable && hal.spindle.cap.variable;
}
// [0. Non-specific/common error-checks and miscellaneous setup]:
@@ -2536,7 +2536,7 @@ status_code_t gc_execute_block(char *block)
if (!user_words.s && ((gc_state.spindle.rpm != gc_block.values.s) || gc_parser_flags.spindle_force_sync)) {
if (gc_state.modal.spindle.on && !gc_parser_flags.laser_is_motion)
spindle_sync(gc_state.modal.spindle, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s);
spindle_sync(0, gc_state.modal.spindle, gc_parser_flags.laser_disable ? 0.0f : gc_block.values.s);
gc_state.spindle.rpm = gc_block.values.s; // Update spindle speed state.
}
@@ -2634,7 +2634,7 @@ status_code_t gc_execute_block(char *block)
// Update spindle control and apply spindle speed when enabling it in this block.
// NOTE: All spindle state changes are synced, even in laser mode. Also, plan_data,
// rather than gc_state, is used to manage laser state for non-laser motions.
if(spindle_sync(gc_block.modal.spindle, plan_data.spindle.rpm))
if(spindle_sync(0, gc_block.modal.spindle, plan_data.spindle.rpm))
gc_state.modal.spindle = gc_block.modal.spindle;
}

6
grbl.h
View File

@@ -34,7 +34,7 @@
#else
#define GRBL_VERSION "1.1f"
#endif
#define GRBL_BUILD 20220215
#define GRBL_BUILD 20220325
// The following symbols are set here if not already set by the compiler or in config.h
// Do NOT change here!
@@ -80,10 +80,6 @@
#define SAFETY_DOOR_COOLANT_DELAY 1.0f // Float (seconds)
#endif
#ifndef SPINDLE_RPM_CONTROLLED
#define SPINDLE_PWM_DIRECT
#endif
#ifndef SLEEP_DURATION
#define SLEEP_DURATION 5.0f // Number of minutes before sleep mode is entered.
#endif

View File

@@ -201,24 +201,26 @@ int grbl_enter (void)
if(driver.ok == 0xFF)
driver.setup = hal.driver_setup(&settings);
spindle_select(settings.spindle.flags.type);
#ifdef ENABLE_SPINDLE_LINEARIZATION
driver.linearization = hal.driver_cap.spindle_pwm_linearization;
#endif
#ifdef SPINDLE_PWM_DIRECT
driver.spindle = (!hal.driver_cap.variable_spindle || (hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL));
#endif
if(grbl.on_spindle_select)
grbl.on_spindle_select(hal.driver_cap.dual_spindle && settings.mode == Mode_Laser ? 0 : 1);
driver.spindle = hal.spindle.get_pwm == NULL || hal.spindle.update_pwm != NULL;
if(driver.ok != 0xFF) {
sys.alarm = Alarm_SelftestFailed;
protocol_enqueue_rt_command(report_driver_error);
}
if(hal.spindle.set_state)
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
hal.coolant.set_state((coolant_state_t){0});
if(hal.get_position)
hal.get_position(&sys.position); // TODO: restore on abort when returns true?
hal.get_position(&sys.position); // TODO: restore on abort when returns true?
#ifdef COREXY
corexy_init();

89
hal.h
View File

@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2016-2021 Terje Io
Copyright (c) 2016-2022 Terje Io
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,30 +45,25 @@ typedef union {
uint32_t value; //!< All bitmap flags.
struct {
uint32_t mist_control :1, //!< Mist control (M7) is supported.
variable_spindle :1, //!< Variable spindle speed is supported.
spindle_dir :1, //!< Spindle direction (M4) is supported.
software_debounce :1, //!< Software debounce of input switches signals is supported.
step_pulse_delay :1, //!< Stepper step pulse delay is supported.
limits_pull_up :1, //!< Pullup resistors for limit inputs are are supported.
control_pull_up :1, //!< Pullup resistors for control inputs are supported.
probe_pull_up :1, //!< Pullup resistors for probe inputs are supported.
amass_level :2, // 0...3 Deprecated?
spindle_at_speed :1, //!< Spindle at speed feedback is supported.
laser_ppi_mode :1, //!< Laser PPI (Pulses Per Inch) mode is supported.
spindle_sync :1, //!< Spindle synced motion is supported.
sd_card :1,
bluetooth :1,
ethernet :1,
wifi :1,
spindle_pwm_invert :1, //!< Spindle PWM output can be inverted.
spindle_pid :1,
mpg_mode :1,
spindle_pwm_linearization :1,
laser_ppi_mode :1, //!< Laser PPI (Pulses Per Inch) mode is supported.
atc :1, //!< Automatic tool changer (ATC) is supported.
no_gcode_message_handling :1,
dual_spindle :1,
odometers :1,
unassigned :7;
unassigned :12;
};
} driver_cap_t;
@@ -116,84 +111,6 @@ The callback function will be called for each pin.
*/
typedef void (*enumerate_pins_ptr)(bool low_level, pin_info_ptr callback);
/*************
* Spindle *
*************/
/*! \brief Pointer to function for setting the spindle state.
\param state a \a spindle_state_t union variable.
\param rpm spindle RPM.
*/
typedef void (*spindle_set_state_ptr)(spindle_state_t state, float rpm);
/*! \brief Pointer to function for getting the spindle state.
\returns state in a \a spindle_state_t union variable.
*/
typedef spindle_state_t (*spindle_get_state_ptr)(void);
#ifdef SPINDLE_PWM_DIRECT
/*! \brief Pointer to function for converting a RPM value to a PWM value.
Typically this is a wrapper for the spindle_compute_pwm_value() function provided by the core.
\param rpm spindle RPM.
\returns the corresponding PWM value.
*/
typedef uint_fast16_t (*spindle_get_pwm_ptr)(float rpm);
/*! \brief Pointer to function for updating spindle speed on the fly.
\param pwm new spindle PWM value.
\returns the actual PWM value used.
__NOTE:__ this function will be called from an interrupt context.
*/
typedef void (*spindle_update_pwm_ptr)(uint_fast16_t pwm);
#else
typedef void (*spindle_update_rpm_ptr)(float rpm);
#endif
/*! \brief Pointer to function for getting spindle data.
\param request request type as a \a #spindle_data_request_t enum.
\returns pointer to the requested information in a spindle_data_t structure.
__NOTE:__ this function requires input from a spindle encoder.
*/
typedef spindle_data_t *(*spindle_get_data_ptr)(spindle_data_request_t request);
/*! \brief Pointer to function for resetting spindle data. */
typedef void (*spindle_reset_data_ptr)(void);
/*! \brief Pointer to function for outputting a spindle on pulse.
Used for Pulses Per Inch (PPI) laser mode.
\param pulse_length spindle on length in microseconds.
*/
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
//! Handlers for spindle support.
typedef struct {
spindle_set_state_ptr set_state; //!< Handler for setting spindle state.
spindle_get_state_ptr get_state; //!< Handler for getting spindle state.
#ifdef SPINDLE_PWM_DIRECT
spindle_get_pwm_ptr get_pwm; //!< Handler for calculating spindle PWM value from RPM.
spindle_update_pwm_ptr update_pwm; //!< Handler for updating spindle PWM output.
#else
spindle_update_rpm_ptr update_rpm; //!< Handler for updating spindle RPM.
#endif
#ifdef GRBL_ESP32
void (*esp32_off)(void); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
#endif
// Optional entry points:
spindle_get_data_ptr get_data; //!< Optional handler for getting spindle data. Required for spindle sync.
spindle_reset_data_ptr reset_data; //!< Optional handler for resetting spindle data. Required for spindle sync.
spindle_pulse_on_ptr pulse_on; //!< Optional handler for Pulses Per Inch (PPI) mode. Required for the laser PPI plugin.
} spindle_ptrs_t;
/*************
* Coolant *
*************/

View File

@@ -572,7 +572,7 @@ void mc_canned_drill (motion_mode_t motion, float *target, plan_line_data_t *pl_
return;
if(canned->spindle_off)
spindle_sync(gc_state.modal.spindle, pl_data->spindle.rpm);
spindle_sync(0, gc_state.modal.spindle, pl_data->spindle.rpm);
}
// rapid move to next position if incremental mode

View File

@@ -34,9 +34,11 @@
#endif
#if VFD_ENABLE
extern void vfd_init (void);
vfd_init();
#if DUAL_SPINDLE
#if VFD_ENABLE == 1 || VFD_ENABLE == 2 || VFD_ENABLE == -1
extern void vfd_huanyang_init (void);
vfd_huanyang_init();
#endif
#if N_SPINDLE > 1
extern void spindle_select_init(void);
spindle_select_init();
#endif

View File

@@ -732,7 +732,7 @@ void report_gcode_modes (void)
hal.stream.write(" G");
hal.stream.write(uitoa((uint32_t)(94 - gc_state.modal.feed_mode)));
if(sys.mode == Mode_Lathe && hal.driver_cap.variable_spindle)
if(sys.mode == Mode_Lathe && hal.spindle.cap.variable)
hal.stream.write(gc_state.modal.spindle_rpm_mode == SpindleSpeedMode_RPM ? " G97" : " G96");
#if COMPATIBILITY_LEVEL < 10
@@ -817,7 +817,7 @@ void report_gcode_modes (void)
hal.stream.write(appendbuf(2, " F", get_rate_value(gc_state.feed_rate)));
if(hal.driver_cap.variable_spindle)
if(hal.spindle.cap.variable)
hal.stream.write(appendbuf(2, " S", ftoa(gc_state.spindle.rpm, N_DECIMAL_RPMVALUE)));
hal.stream.write("]" ASCII_EOL);
@@ -858,7 +858,7 @@ void report_build_info (char *line, bool extended)
strcpy(buf, "[OPT:");
if(hal.driver_cap.variable_spindle)
if(spindle_get_caps().variable)
*append++ = 'V';
*append++ = 'N';
@@ -972,6 +972,9 @@ void report_build_info (char *line, bool extended)
if(settings.mode == Mode_Lathe)
strcat(buf, "LATHE,");
if(hal.driver_cap.laser_ppi_mode)
strcat(buf, "PPI,");
#if NGC_EXPRESSIONS_ENABLE
strcat(buf, "EXPR,");
#endif
@@ -1195,7 +1198,7 @@ void report_realtime_status (void)
// Report realtime feed speed
if(settings.status_report.feed_speed) {
if(hal.driver_cap.variable_spindle) {
if(hal.spindle.cap.variable) {
hal.stream.write_all(appendbuf(2, "|FS:", get_rate_value(st_get_realtime_rate())));
hal.stream.write_all(appendbuf(2, ",", uitoa(sp_state.on ? lroundf(sys.spindle_rpm) : 0)));
if(hal.spindle.get_data /* && sys.mpg_mode */)

View File

@@ -333,6 +333,7 @@ static status_code_t set_report_mask (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_report_inches (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_control_invert (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_control_disable_pullup (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_probe_disable_pullup (setting_id_t id, uint_fast16_t int_value);
static status_code_t set_soft_limits_enable (setting_id_t id, uint_fast16_t int_value);
@@ -376,6 +377,7 @@ static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block d
static char spindle_signals[] = "Spindle enable,Spindle direction,PWM";
static char coolant_signals[] = "Flood,Mist";
static char ganged_axes[] = "X-Axis,Y-Axis,Z-Axis";
static char spindle_types[100] = "";
PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", "2.0", NULL, Setting_IsLegacy, &settings.steppers.pulse_microseconds, NULL, NULL },
@@ -511,6 +513,7 @@ PROGMEM static const setting_detail_t setting_detail[] = {
{ Setting_DoorCoolantOnDelay, Group_SafetyDoor, "Coolant on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.coolant_on_delay, NULL, is_setting_available },
#endif
{ Setting_SpindleOnDelay, Group_Spindle, "Spindle on delay", "s", Format_Decimal, "#0.0", "0.5", "20", Setting_IsExtended, &settings.safety_door.spindle_on_delay, NULL, is_setting_available },
{ Setting_SpindleType, Group_Spindle, "Default spindle", NULL, Format_RadioButtons, spindle_types, NULL, NULL, Setting_IsExtendedFn, set_spindle_type, get_int, is_setting_available },
};
#ifndef NO_SETTINGS_DESCRIPTIONS
@@ -652,6 +655,7 @@ PROGMEM static const setting_descr_t setting_descr[] = {
#else
{ Setting_DoorSpindleOnDelay, "Delay to allow spindle to spin up when spindle at speed tolerance is > 0." },
#endif
{ Setting_SpindleType, "Spindle selected on startup." },
};
#endif
@@ -791,10 +795,24 @@ static status_code_t set_control_invert (setting_id_t id, uint_fast16_t int_valu
return Status_OK;
}
static status_code_t set_spindle_type (setting_id_t id, uint_fast16_t int_value)
{
if(spindle_get_count() < 2)
return Status_SettingDisabled;
else if(int_value >= spindle_get_count())
return Status_SettingValueOutOfRange;
settings.spindle.flags.type = int_value;
spindle_select(settings.spindle.flags.type);
return Status_OK;
}
static status_code_t set_spindle_invert (setting_id_t id, uint_fast16_t int_value)
{
settings.spindle.invert.mask = int_value;
if(settings.spindle.invert.pwm && !hal.driver_cap.spindle_pwm_invert) {
if(settings.spindle.invert.pwm && !spindle_get_caps().pwm_invert) {
settings.spindle.invert.pwm = Off;
return Status_SettingDisabled;
}
@@ -896,7 +914,7 @@ static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
break;
case Mode_Laser:
if(!hal.driver_cap.variable_spindle)
if(!spindle_get_caps().laser)
return Status_SettingDisabledLaser;
if(settings.mode != Mode_Laser)
settings.flags.disable_laser_during_hold = DEFAULT_ENABLE_LASER_DURING_HOLD;
@@ -911,7 +929,8 @@ static status_code_t set_mode (setting_id_t id, uint_fast16_t int_value)
return Status_InvalidStatement;
}
settings.mode = sys.mode = (machine_mode_t)int_value;
settings.mode = (machine_mode_t)int_value;
sys.mode = settings.mode == Mode_Laser && !hal.spindle.cap.laser ? Mode_Standard : settings.mode;
return Status_OK;
}
@@ -1301,6 +1320,10 @@ static uint32_t get_int (setting_id_t id)
value = settings.flags.g92_is_volatile;
break;
case Setting_SpindleType:
value = settings.spindle.flags.type;
break;
#if N_AXIS > 3
case Settings_Axis_Rotational:
value = (settings.steppers.is_rotational.mask & AXES_BITMASK) >> 3;
@@ -1403,7 +1426,7 @@ static bool is_setting_available (const setting_detail_t *setting)
break;
case Setting_SpindlePWMBehaviour:
available = hal.driver_cap.variable_spindle;
available = spindle_get_caps().variable;
break;
case Setting_InvertProbePin:
@@ -1415,6 +1438,10 @@ static bool is_setting_available (const setting_detail_t *setting)
available = hal.probe.get_state != NULL;
break;
case Setting_SpindleType:
available = spindle_get_count() > 1;
break;
case Setting_SpindlePPR:
available = hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid;
break;
@@ -1425,7 +1452,7 @@ static bool is_setting_available (const setting_detail_t *setting)
case Setting_PWMOffValue:
case Setting_PWMMinValue:
case Setting_PWMMaxValue:
available = hal.driver_cap.variable_spindle;
available = spindle_get_caps().variable;
break;
case Setting_DualAxisLengthFailPercent:
@@ -1452,11 +1479,11 @@ static bool is_setting_available (const setting_detail_t *setting)
#endif
case Setting_SpindleAtSpeedTolerance:
available = hal.driver_cap.spindle_at_speed;
available = hal.spindle.cap.at_speed;
break;
case Setting_SpindleOnDelay:
available = !hal.signals_cap.safety_door_ajar && hal.driver_cap.spindle_at_speed;
available = !hal.signals_cap.safety_door_ajar && hal.spindle.cap.at_speed;
break;
default:
@@ -1578,9 +1605,12 @@ bool read_global_settings ()
bool ok = hal.nvs.type != NVS_None && SETTINGS_VERSION == hal.nvs.get_byte(0) && hal.nvs.memcpy_from_nvs((uint8_t *)&settings, NVS_ADDR_GLOBAL, sizeof(settings_t), true) == NVS_TransferResult_OK;
// Sanity check of settings, board map could have been changed...
if(settings.mode == Mode_Laser && !hal.driver_cap.variable_spindle)
if(settings.mode == Mode_Laser && !spindle_get_caps().laser)
settings.mode = Mode_Standard;
if(settings.spindle.flags.type >= spindle_get_count())
settings.spindle.flags.type = 0;
sys.mode = settings.mode;
if(!(hal.driver_cap.spindle_sync || hal.driver_cap.spindle_pid))
@@ -1620,10 +1650,10 @@ void settings_restore (settings_restore_t restore)
memcpy(&settings, &defaults, sizeof(settings_t));
sys.mode = settings.mode;
sys.mode = settings.mode == Mode_Laser && !hal.spindle.cap.laser ? Mode_Standard : settings.mode;
settings.control_invert.mask &= hal.signals_cap.mask;
settings.spindle.invert.ccw &= hal.driver_cap.spindle_dir;
settings.spindle.invert.pwm &= hal.driver_cap.spindle_pwm_invert;
settings.spindle.invert.ccw &= spindle_get_caps().direction;
settings.spindle.invert.pwm &= spindle_get_caps().pwm_invert;
#ifdef ENABLE_BACKLASH_COMPENSATION
mc_backlash_init((axes_signals_t){AXES_BITMASK});
#endif
@@ -2157,19 +2187,34 @@ status_code_t settings_store_setting (setting_id_t id, char *svalue)
if(status == Status_OK) {
if(!hal.spindle.cap.rpm_range_locked) {
hal.spindle.rpm_min = settings.spindle.rpm_min;
hal.spindle.rpm_max = settings.spindle.rpm_max;
}
if(set->save)
set->save();
if(set->on_changed)
set->on_changed(&settings);
if(set == &setting_details && grbl.on_spindle_select)
grbl.on_spindle_select(hal.driver_cap.dual_spindle && settings.mode == Mode_Laser ? 0 : 1);
}
return status;
}
bool settings_add_spindle_type (const char *type)
{
bool ok;
if((ok = strlen(spindle_types) + strlen(type) + 1 < sizeof(spindle_types))) {
if(*spindle_types != '\0')
strcat(spindle_types, ",");
strcat(spindle_types, type);
}
return ok;
}
// Initialize the config subsystem
void settings_init (void)
{
@@ -2202,12 +2247,16 @@ void settings_init (void)
hal.probe.configure(false, false);
}
if(spindle_get_count() == 0)
spindle_add_null();
spindle_state_t spindle_cap = {
.on = On,
.ccw = hal.driver_cap.spindle_dir,
.pwm = hal.driver_cap.spindle_pwm_invert
};
spindle_cap.ccw = spindle_get_caps().direction;
spindle_cap.pwm = spindle_get_caps().pwm_invert;
setting_remove_elements(Setting_SpindleInvertMask, spindle_cap.mask);
setting_remove_elements(Setting_ControlInvertMask, hal.signals_cap.mask);

View File

@@ -255,6 +255,7 @@ typedef enum {
Setting_DoorSpindleOnDelay = 392,
Setting_DoorCoolantOnDelay = 393,
Setting_SpindleOnDelay = 394, // made available if safety door input not provided
Setting_SpindleType = 395,
Setting_EncoderSettingsBase = 400, // NOTE: Reserving settings values >= 400 for encoder settings. Up to 449.
Setting_EncoderSettingsMax = 449,
@@ -425,7 +426,8 @@ typedef union {
uint8_t mask;
struct {
uint8_t pwm_action :2,
unassigned :6;
type :3,
unassigned :3;
};
} spindle_settings_flags_t;
@@ -790,5 +792,6 @@ char *setting_get_value (const setting_detail_t *setting, uint_fast16_t offset);
setting_id_t settings_get_axis_base (setting_id_t id, uint_fast8_t *idx);
bool setting_is_list (const setting_detail_t *setting);
void setting_remove_elements (setting_id_t id, uint32_t mask);
bool settings_add_spindle_type (const char *type);
#endif

View File

@@ -22,11 +22,157 @@
*/
#include <math.h>
#include <string.h>
#include "hal.h"
#include "protocol.h"
#include "state_machine.h"
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
static uint8_t n_spindle = 0;
static const spindle_ptrs_t *spindles[N_SPINDLE];
spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name)
{
if(n_spindle == 0)
memcpy(&hal.spindle, spindle, sizeof(spindle_ptrs_t));
if(n_spindle < N_SPINDLE && settings_add_spindle_type(name)) {
spindles[n_spindle++] = spindle;
return n_spindle - 1;
}
return -1;
}
bool spindle_select (spindle_id_t spindle_id)
{
bool ok;
if(n_spindle == 0) {
if(hal.spindle.set_state)
spindles[n_spindle++] = &hal.spindle;
else
spindle_add_null();
}
if((ok = spindle_id >= 0 && spindle_id < n_spindle)) {
if(hal.spindle.set_state && hal.spindle.set_state != spindles[spindle_id]->set_state)
gc_spindle_off();
if(ok) {
spindle_ptrs_t spindle_org;
memcpy(&spindle_org, &hal.spindle, offsetof(spindle_ptrs_t, get_data));
memcpy(&hal.spindle, spindles[spindle_id], offsetof(spindle_ptrs_t, get_data));
if(!hal.spindle.cap.rpm_range_locked) {
hal.spindle.rpm_min = settings.spindle.rpm_min;
hal.spindle.rpm_max = settings.spindle.rpm_max;
}
if(spindles[spindle_id]->config)
ok = spindles[spindle_id]->config();
if(ok) {
sys.mode = settings.mode == Mode_Laser && !hal.spindle.cap.laser ? Mode_Standard : settings.mode;
if(grbl.on_spindle_select)
grbl.on_spindle_select(spindle_id);
} else
memcpy(&spindle_org, &hal.spindle, offsetof(spindle_ptrs_t, get_data));
}
}
return ok;
}
const spindle_ptrs_t *spindle_get (spindle_id_t spindle_id)
{
if(spindle_id >= 0 && spindle_id < n_spindle)
return spindles[spindle_id];
return NULL;
}
spindle_cap_t spindle_get_caps (void)
{
spindle_cap_t caps = {0};
uint_fast8_t idx = n_spindle;
if(!idx)
caps.value = hal.spindle.cap.value;
else do {
caps.value |= spindles[--idx]->cap.value;
} while(idx);
return caps;
}
uint8_t spindle_get_count (void)
{
if(n_spindle == 0)
spindle_select(0);
return n_spindle;
}
//
// Null (dummy) spindle, automatically installed if no spindles are registered.
//
static void null_set_state (spindle_state_t state, float rpm)
{
UNUSED(state);
UNUSED(rpm);
}
static spindle_state_t null_get_state (void)
{
return (spindle_state_t){0};
}
// Sets spindle speed
static void null_update_pwm (uint_fast16_t pwm_value)
{
UNUSED(pwm_value);
}
static uint_fast16_t null_get_pwm (float rpm)
{
UNUSED(rpm);
return 0;
}
static void null_update_rpm (float rpm)
{
UNUSED(rpm);
}
void spindle_add_null (void)
{
static const spindle_ptrs_t spindle = {
.cap.variable = Off,
.cap.at_speed = Off,
.cap.direction = Off,
.set_state = null_set_state,
.get_state = null_get_state,
.get_pwm = null_get_pwm,
.update_pwm = null_update_pwm,
.update_rpm = null_update_rpm
};
spindle_register(&spindle, "NULL");
}
// End null (dummy) spindle.
// Set spindle speed override
// NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
void spindle_set_override (uint_fast8_t speed_override)
@@ -39,7 +185,7 @@ void spindle_set_override (uint_fast8_t speed_override)
if ((uint8_t)speed_override != sys.override.spindle_rpm) {
sys.override.spindle_rpm = (uint8_t)speed_override;
if(state_get() == STATE_IDLE)
spindle_set_state(gc_state.modal.spindle, gc_state.spindle.rpm);
spindle_set_state(0, gc_state.modal.spindle, gc_state.spindle.rpm);
else
sys.step_control.update_spindle_rpm = On;
sys.report.overrides = On; // Set to report change immediately
@@ -49,20 +195,20 @@ void spindle_set_override (uint_fast8_t speed_override)
// Immediately sets spindle running state with direction and spindle rpm, if enabled.
// Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
// sleep, and spindle stop override.
bool spindle_set_state (spindle_state_t state, float rpm)
static bool set_state (const spindle_ptrs_t *spindle, spindle_state_t state, float rpm)
{
if (!ABORTED) { // Block during abort.
if (!state.on) { // Halt or set spindle direction and rpm.
sys.spindle_rpm = rpm = 0.0f;
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
spindle->set_state((spindle_state_t){0}, 0.0f);
} else {
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
// TODO: alarm/interlock if going from CW to CCW directly in non-laser mode?
if (sys.mode == Mode_Laser && state.ccw)
rpm = 0.0f; // TODO: May need to be rpm_min*(100/MAX_SPINDLE_RPM_OVERRIDE);
hal.spindle.set_state(state, spindle_set_rpm(rpm, sys.override.spindle_rpm));
spindle->set_state(state, spindle_set_rpm(rpm, sys.override.spindle_rpm));
}
sys.report.spindle = On; // Set to report change immediately
@@ -72,18 +218,28 @@ bool spindle_set_state (spindle_state_t state, float rpm)
return !ABORTED;
}
// Immediately sets spindle running state with direction and spindle rpm, if enabled.
// Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
// sleep, and spindle stop override.
bool spindle_set_state (spindle_id_t spindle_id, spindle_state_t state, float rpm)
{
return set_state(spindle_id == 0 ? &hal.spindle : spindles[spindle_id], state, rpm);
}
// G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails
// if an abort or check-mode is active.
bool spindle_sync (spindle_state_t state, float rpm)
bool spindle_sync (spindle_id_t spindle_id, spindle_state_t state, float rpm)
{
bool ok;
if (!(ok = state_get() == STATE_CHECK_MODE)) {
bool at_speed = !state.on || !hal.driver_cap.spindle_at_speed || settings.spindle.at_speed_tolerance <= 0.0f;
const spindle_ptrs_t *spindle = spindle_id == 0 ? &hal.spindle : spindles[spindle_id];
bool at_speed = !state.on || !spindle->cap.at_speed || settings.spindle.at_speed_tolerance <= 0.0f;
// Empty planner buffer to ensure spindle is set when programmed.
if((ok = protocol_buffer_synchronize()) && spindle_set_state(state, rpm) && !at_speed) {
if((ok = protocol_buffer_synchronize()) && set_state(spindle, state, rpm) && !at_speed) {
float on_delay = 0.0f;
while(!(at_speed = hal.spindle.get_state().at_speed)) {
delay_sec(0.2f, DelayMode_Dwell);
@@ -112,9 +268,9 @@ bool spindle_restore (spindle_state_t state, float rpm)
if(sys.mode == Mode_Laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
sys.step_control.update_spindle_rpm = On;
else { // TODO: add check for current spindle state matches restore state?
spindle_set_state(state, rpm);
spindle_set_state(0, state, rpm);
if(state.on) {
if((ok = !hal.driver_cap.spindle_at_speed))
if((ok = !hal.spindle.cap.at_speed))
delay_sec(settings.safety_door.spindle_on_delay, DelayMode_SysSuspend);
else if((ok == (settings.spindle.at_speed_tolerance <= 0.0f))) {
float delay = 0.0f;
@@ -144,10 +300,10 @@ float spindle_set_rpm (float rpm, uint8_t override_pct)
// Apply RPM limits
if (rpm <= 0.0f)
rpm = 0.0f;
else if (rpm > settings.spindle.rpm_max)
rpm = settings.spindle.rpm_max;
else if (rpm < settings.spindle.rpm_min)
rpm = settings.spindle.rpm_min;
else if (rpm > hal.spindle.rpm_max)
rpm = hal.spindle.rpm_max;
else if (rpm < hal.spindle.rpm_min)
rpm = hal.spindle.rpm_min;
sys.spindle_rpm = rpm;
@@ -168,7 +324,7 @@ static inline uint_fast16_t invert_pwm (spindle_pwm_t *pwm_data, uint_fast16_t p
// Returns false if no PWM range possible, driver should revert to simple on/off spindle control if so.
bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz)
{
if(settings.spindle.rpm_max > settings.spindle.rpm_min) {
if(hal.spindle.rpm_max > hal.spindle.rpm_min) {
pwm_data->period = (uint_fast16_t)((float)clock_hz / settings.spindle.pwm_freq);
if(settings.spindle.pwm_off_value == 0.0f)
pwm_data->off_value = pwm_data->invert_pwm ? pwm_data->period : 0;
@@ -176,7 +332,7 @@ bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz)
pwm_data->off_value = invert_pwm(pwm_data, (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_off_value / 100.0f));
pwm_data->min_value = (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_min_value / 100.0f);
pwm_data->max_value = (uint_fast16_t)(pwm_data->period * settings.spindle.pwm_max_value / 100.0f) + pwm_data->offset;
pwm_data->pwm_gradient = (float)(pwm_data->max_value - pwm_data->min_value) / (settings.spindle.rpm_max - settings.spindle.rpm_min);
pwm_data->pwm_gradient = (float)(pwm_data->max_value - pwm_data->min_value) / (hal.spindle.rpm_max - hal.spindle.rpm_min);
pwm_data->always_on = settings.spindle.pwm_off_value != 0.0f;
}
@@ -191,7 +347,7 @@ bool spindle_precompute_pwm_values (spindle_pwm_t *pwm_data, uint32_t clock_hz)
}
#endif
return settings.spindle.rpm_max > settings.spindle.rpm_min;
return hal.spindle.rpm_max > hal.spindle.rpm_min;
}
// Spindle RPM to PWM conversion.
@@ -199,7 +355,7 @@ uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, boo
{
uint_fast16_t pwm_value;
if(rpm > settings.spindle.rpm_min) {
if(rpm > hal.spindle.rpm_min) {
#ifdef ENABLE_SPINDLE_LINEARIZATION
// Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
uint_fast8_t idx = pwm_data->n_pieces;
@@ -215,7 +371,7 @@ uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, boo
} else
#endif
// Compute intermediate PWM value with linear spindle speed model.
pwm_value = (uint_fast16_t)floorf((rpm - settings.spindle.rpm_min) * pwm_data->pwm_gradient) + pwm_data->min_value;
pwm_value = (uint_fast16_t)floorf((rpm - hal.spindle.rpm_min) * pwm_data->pwm_gradient) + pwm_data->min_value;
if(pwm_value >= (pid_limit ? pwm_data->period : pwm_data->max_value))
pwm_value = pid_limit ? pwm_data->period - 1 : pwm_data->max_value;

View File

@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2017-2021 Terje Io
Copyright (c) 2017-2022 Terje Io
Copyright (c) 2012-2015 Sungeun K. Jeon
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -24,6 +24,8 @@
#ifndef _SPINDLE_CONTROL_H_
#define _SPINDLE_CONTROL_H_
typedef int8_t spindle_id_t;
typedef union {
uint8_t value;
uint8_t mask;
@@ -34,11 +36,122 @@ typedef union {
reserved3 :1,
reserved4 :1,
encoder_error :1,
at_speed :1,
at_speed :1, //!< Spindle is at speed.
synchronized :1;
};
} spindle_state_t;
/// Bitmap flags for spindle capabilities.
typedef union {
uint8_t value; //!< All bitmap flags.
struct {
uint8_t variable :1, //!< Variable spindle speed is supported.
direction :1, //!< Spindle direction (M4) is supported.
at_speed :1, //!< Spindle at speed feedback is supported.
laser :1, //!< Spindle can control a laser.
pwm_invert :1, //!< Spindle PWM output can be inverted.
pid :1,
pwm_linearization :1,
rpm_range_locked :1; //!< Spindle RPM range (min, max) not inherited from settings.
};
} spindle_cap_t;
// Used when HAL driver supports spindle synchronization
typedef struct {
float rpm;
float rpm_low_limit;
float rpm_high_limit;
float angular_position; // Number of revolutions since last reset
float rpm_programmed;
uint32_t index_count;
uint32_t pulse_count;
uint32_t error_count;
spindle_state_t state_programmed;
} spindle_data_t;
typedef enum {
SpindleData_Counters, //!< 0
SpindleData_RPM, //!< 1
SpindleData_AngularPosition //!< 2
} spindle_data_request_t;
/*! \brief Pointer to function for configuring the spindle.
\returns state in a \a spindle_state_t union variable.
*/
typedef bool (*spindle_config_ptr)(void);
/*! \brief Pointer to function for setting the spindle state.
\param state a \a spindle_state_t union variable.
\param rpm spindle RPM.
*/
typedef void (*spindle_set_state_ptr)(spindle_state_t state, float rpm);
/*! \brief Pointer to function for getting the spindle state.
\returns state in a \a spindle_state_t union variable.
*/
typedef spindle_state_t (*spindle_get_state_ptr)(void);
/*! \brief Pointer to function for converting a RPM value to a PWM value.
Typically this is a wrapper for the spindle_compute_pwm_value() function provided by the core.
\param rpm spindle RPM.
\returns the corresponding PWM value.
*/
typedef uint_fast16_t (*spindle_get_pwm_ptr)(float rpm);
/*! \brief Pointer to function for updating spindle speed on the fly.
\param pwm new spindle PWM value.
\returns the actual PWM value used.
__NOTE:__ this function will be called from an interrupt context.
*/
typedef void (*spindle_update_pwm_ptr)(uint_fast16_t pwm);
/*! \brief Pointer to function for updating spindle RPM.
\param rpm spindle RPM.
*/
typedef void (*spindle_update_rpm_ptr)(float rpm);
/*! \brief Pointer to function for getting spindle data.
\param request request type as a \a #spindle_data_request_t enum.
\returns pointer to the requested information in a spindle_data_t structure.
__NOTE:__ this function requires input from a spindle encoder.
*/
typedef spindle_data_t *(*spindle_get_data_ptr)(spindle_data_request_t request);
/*! \brief Pointer to function for resetting spindle data. */
typedef void (*spindle_reset_data_ptr)(void);
/*! \brief Pointer to function for outputting a spindle on pulse.
Used for Pulses Per Inch (PPI) laser mode.
\param pulse_length spindle on length in microseconds.
*/
typedef void (*spindle_pulse_on_ptr)(uint_fast16_t pulse_length);
//! Handlers for spindle support.
typedef struct {
spindle_cap_t cap; //!< Spindle capabilities.
float rpm_min; //!< Minimum spindle RPM.
float rpm_max; //!< Maximum spindle RPM.
spindle_config_ptr config; //!< Optional handler for configuring the spindle.
spindle_set_state_ptr set_state; //!< Handler for setting spindle state.
spindle_get_state_ptr get_state; //!< Handler for getting spindle state.
spindle_get_pwm_ptr get_pwm; //!< Handler for calculating spindle PWM value from RPM.
spindle_update_pwm_ptr update_pwm; //!< Handler for updating spindle PWM output.
spindle_update_rpm_ptr update_rpm; //!< Handler for updating spindle RPM.
#ifdef GRBL_ESP32
void (*esp32_off)(void); //!< Workaround handler for snowflake ESP32 Guru awaken by floating point data in ISR context.
#endif
// Optional entry points:
spindle_pulse_on_ptr pulse_on; //!< Optional handler for Pulses Per Inch (PPI) mode. Required for the laser PPI plugin.
spindle_get_data_ptr get_data; //!< Optional handler for getting spindle data. Required for spindle sync.
spindle_reset_data_ptr reset_data; //!< Optional handler for resetting spindle data. Required for spindle sync.
} spindle_ptrs_t;
typedef struct {
float rpm;
float start;
@@ -59,25 +172,6 @@ typedef struct {
pwm_piece_t piece[SPINDLE_NPWM_PIECES];
} spindle_pwm_t;
// Used when HAL driver supports spindle synchronization
typedef struct {
float rpm;
float rpm_low_limit;
float rpm_high_limit;
float angular_position; // Number of revolutions since last reset
float rpm_programmed;
uint32_t index_count;
uint32_t pulse_count;
uint32_t error_count;
spindle_state_t state_programmed;
} spindle_data_t;
typedef enum {
SpindleData_Counters, //!< 0
SpindleData_RPM, //!< 1
SpindleData_AngularPosition //!< 2
} spindle_data_request_t;
void spindle_set_override (uint_fast8_t speed_override);
// Called by g-code parser when setting spindle state and requires a buffer sync.
@@ -85,10 +179,10 @@ void spindle_set_override (uint_fast8_t speed_override);
// Called by spindle_sync() after sync and parking motion/spindle stop override during restore.
// Called by g-code parser when setting spindle state and requires a buffer sync.
bool spindle_sync (spindle_state_t state, float rpm);
bool spindle_sync (spindle_id_t spindle_id, spindle_state_t state, float rpm);
// Sets spindle running state with direction, enable, and spindle RPM.
bool spindle_set_state (spindle_state_t state, float rpm);
bool spindle_set_state (spindle_id_t spindle_id, spindle_state_t state, float rpm);
// Spindle speed calculation and limit handling
float spindle_set_rpm (float rpm, uint8_t speed_override);
@@ -117,4 +211,13 @@ Typically this is done in the \a hal.driver_setup handler.
*/
uint_fast16_t spindle_compute_pwm_value (spindle_pwm_t *pwm_data, float rpm, bool pid_limit);
spindle_id_t spindle_register (const spindle_ptrs_t *spindle, const char *name);
void spindle_add_null (void);
uint8_t spindle_get_count (void);
bool spindle_select (spindle_id_t spindle_id);
spindle_cap_t spindle_get_caps (void);
#endif

View File

@@ -260,7 +260,7 @@ void state_suspend_manager (void)
// Handles beginning of spindle stop
if (sys.override.spindle_stop.initiate) {
sys.override.spindle_stop.value = 0; // Clear stop override state
spindle_set_state((spindle_state_t){0}, 0.0f); // De-energize
spindle_set_state(0, (spindle_state_t){0}, 0.0f); // De-energize
sys.override.spindle_stop.enabled = On; // Set stop override state to enabled, if de-energized.
}
@@ -270,13 +270,13 @@ void state_suspend_manager (void)
if (sys.mode == Mode_Laser) // When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
sys.step_control.update_spindle_rpm = On;
else
spindle_set_state(restore_condition.spindle, restore_spindle_rpm);
spindle_set_state(0, restore_condition.spindle, restore_spindle_rpm);
sys.override.spindle_stop.value = 0; // Clear stop override state
}
} else if (sys.step_control.update_spindle_rpm && hal.spindle.get_state().on) {
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
spindle_set_state(restore_condition.spindle, restore_spindle_rpm);
spindle_set_state(0, restore_condition.spindle, restore_spindle_rpm);
sys.step_control.update_spindle_rpm = Off;
}
}

View File

@@ -399,13 +399,10 @@ ISR_CODE void ISR_FUNC(stepper_driver_interrupt_handler)(void)
#endif
#endif
if(st.exec_segment->update_rpm) {
#ifdef SPINDLE_PWM_DIRECT
if(st.exec_segment->update_pwm)
hal.spindle.update_pwm(st.exec_segment->spindle_pwm);
#else
else if(st.exec_segment->update_rpm)
hal.spindle.update_rpm(st.exec_segment->spindle_rpm);
#endif
}
} else {
// Segment buffer empty. Shutdown.
st_go_idle();
@@ -869,7 +866,7 @@ void st_prep_buffer (void)
// Set new segment to point to the current segment data block.
prep_segment->exec_block = st_prep_block;
prep_segment->update_rpm = false;
prep_segment->update_rpm = prep_segment->update_pwm = false;
/*------------------------------------------------------------------------------------
Compute the average velocity of this new segment by determining the total distance
@@ -998,13 +995,13 @@ void st_prep_buffer (void)
sys.spindle_rpm = rpm = 0.0f;
if(rpm != prep.current_spindle_rpm) {
#ifdef SPINDLE_PWM_DIRECT
prep.current_spindle_rpm = rpm;
prep_segment->spindle_pwm = hal.spindle.get_pwm(rpm);
#else
prep.current_spindle_rpm = prep_segment->spindle_rpm = rpm;
#endif
prep_segment->update_rpm = true;
if((prep_segment->update_pwm = hal.spindle.get_pwm != NULL)) {
prep.current_spindle_rpm = rpm;
prep_segment->spindle_pwm = hal.spindle.get_pwm(rpm);
} else {
prep_segment->update_rpm = true;
prep.current_spindle_rpm = prep_segment->spindle_rpm = rpm;
}
sys.step_control.update_spindle_rpm = Off;
}
}

View File

@@ -3,7 +3,7 @@
Part of grblHAL
Copyright (c) 2019-2020 Terje Io
Copyright (c) 2019-2022 Terje Io
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -65,11 +65,9 @@ typedef struct st_segment {
float current_rate;
float target_position; //!< Target position of segment relative to block start, used by spindle sync code
uint_fast16_t n_step; //!< Number of step events to be executed for this segment
#ifdef SPINDLE_PWM_DIRECT
uint_fast16_t spindle_pwm; //!< Spindle PWM to be set at the start of segment execution
#else
float spindle_rpm; //!< Spindle RPM to be set at the start of the segment execution
#endif
bool update_pwm; //!< True if set spindle speed at the start of the segment execution
bool update_rpm; //!< True if set spindle speed at the start of the segment execution
bool spindle_sync; //!< True if block is spindle synchronized
bool cruising; //!< True when in cruising part of profile, only set for spindle synced moves

View File

@@ -113,7 +113,7 @@ ISR_CODE void ISR_FUNC(control_interrupt_handler)(control_signals_t signals)
// NOTE: at least for lasers there should be an external interlock blocking laser power.
if(state_get() != STATE_IDLE && state_get() != STATE_JOG)
system_set_exec_state_flag(EXEC_SAFETY_DOOR);
if(sys.mode == Mode_Laser) // Turn off spindle imeediately (laser) when in laser mode
if(sys.mode == Mode_Laser) // Turn off spindle immediately (laser) when in laser mode
hal.spindle.set_state((spindle_state_t){0}, 0.0f);
} else
system_set_exec_state_flag(EXEC_SAFETY_DOOR);