mirror of
https://github.com/grblHAL/core.git
synced 2026-02-06 00:52:35 +08:00
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:
@@ -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.
|
||||
|
||||
22
changelog.md
22
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:
|
||||
|
||||
12
config.h
12
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
|
||||
|
||||
@@ -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
14
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;
|
||||
}
|
||||
|
||||
|
||||
6
grbl.h
6
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
|
||||
|
||||
16
grbllib.c
16
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();
|
||||
|
||||
89
hal.h
89
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 *
|
||||
*************/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
11
report.c
11
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 */)
|
||||
|
||||
81
settings.c
81
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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
23
stepper.c
23
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
2
system.c
2
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);
|
||||
|
||||
Reference in New Issue
Block a user