diff --git a/README.md b/README.md index c6d1ded..d98d10d 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/changelog.md b/changelog.md index 9611f4b..897381d 100644 --- a/changelog.md +++ b/changelog.md @@ -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: diff --git a/config.h b/config.h index b4e8c0e..90e600b 100644 --- a/config.h +++ b/config.h @@ -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 diff --git a/core_handlers.h b/core_handlers.h index 064632b..08e99f0 100644 --- a/core_handlers.h +++ b/core_handlers.h @@ -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); diff --git a/gcode.c b/gcode.c index 7a19e50..0673b1c 100644 --- a/gcode.c +++ b/gcode.c @@ -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; } diff --git a/grbl.h b/grbl.h index b520840..0b9c854 100644 --- a/grbl.h +++ b/grbl.h @@ -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 diff --git a/grbllib.c b/grbllib.c index f3b827c..448fd73 100644 --- a/grbllib.c +++ b/grbllib.c @@ -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(); diff --git a/hal.h b/hal.h index bbeb873..a385d2f 100644 --- a/hal.h +++ b/hal.h @@ -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 * *************/ diff --git a/motion_control.c b/motion_control.c index 9392c1b..d01fa7a 100644 --- a/motion_control.c +++ b/motion_control.c @@ -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 diff --git a/plugins_init.h b/plugins_init.h index 7a3cae1..ae8e873 100644 --- a/plugins_init.h +++ b/plugins_init.h @@ -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 diff --git a/report.c b/report.c index f7f2e52..38eef3a 100644 --- a/report.c +++ b/report.c @@ -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 */) diff --git a/settings.c b/settings.c index b2f9733..137b3d6 100644 --- a/settings.c +++ b/settings.c @@ -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); diff --git a/settings.h b/settings.h index d03c471..2434506 100644 --- a/settings.h +++ b/settings.h @@ -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 diff --git a/spindle_control.c b/spindle_control.c index e27e6ac..1fae9ba 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -22,11 +22,157 @@ */ #include +#include #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; diff --git a/spindle_control.h b/spindle_control.h index a939622..42725d6 100644 --- a/spindle_control.h +++ b/spindle_control.h @@ -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 diff --git a/state_machine.c b/state_machine.c index 88aa72a..d8b7fdb 100644 --- a/state_machine.c +++ b/state_machine.c @@ -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; } } diff --git a/stepper.c b/stepper.c index f0572f2..7baef49 100644 --- a/stepper.c +++ b/stepper.c @@ -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; } } diff --git a/stepper.h b/stepper.h index 8531c7d..a592240 100644 --- a/stepper.h +++ b/stepper.h @@ -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 diff --git a/system.c b/system.c index 2b7cd33..688ee6f 100644 --- a/system.c +++ b/system.c @@ -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);