Mass reformat
No code changes other than what clang-format mandates. This is breaking
This commit is contained in:
parent
a1c041481c
commit
fe32d197f9
38 changed files with 7094 additions and 6574 deletions
213
grbl/config.h
213
grbl/config.h
|
|
@ -29,7 +29,6 @@
|
|||
#define config_h
|
||||
#include "grbl.h" // For Arduino IDE compatibility.
|
||||
|
||||
|
||||
// Define CPU pin map and default settings.
|
||||
// NOTE: OEMs can avoid the need to maintain/update the defaults.h and cpu_map.h files and use only
|
||||
// one configuration file by placing their specific defaults and pin map at the bottom of this file.
|
||||
|
|
@ -48,10 +47,10 @@
|
|||
// g-code programs, maybe selected for interface programs.
|
||||
// NOTE: If changed, manually update help message in report.c.
|
||||
|
||||
#define CMD_RESET 0x18 // ctrl-x.
|
||||
#define CMD_RESET 0x18 // ctrl-x.
|
||||
#define CMD_STATUS_REPORT '?'
|
||||
#define CMD_CYCLE_START '~'
|
||||
#define CMD_FEED_HOLD '!'
|
||||
#define CMD_CYCLE_START '~'
|
||||
#define CMD_FEED_HOLD '!'
|
||||
|
||||
// NOTE: All override realtime commands must be in the extended ASCII character set, starting
|
||||
// at character value 128 (0x80) and up to 255 (0xFF). If the normal set of realtime commands,
|
||||
|
|
@ -61,26 +60,26 @@
|
|||
// #define CMD_STATUS_REPORT 0x81
|
||||
// #define CMD_CYCLE_START 0x82
|
||||
// #define CMD_FEED_HOLD 0x83
|
||||
#define CMD_SAFETY_DOOR 0x84
|
||||
#define CMD_JOG_CANCEL 0x85
|
||||
#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
|
||||
#define CMD_FEED_OVR_RESET 0x90 // Restores feed override value to 100%.
|
||||
#define CMD_FEED_OVR_COARSE_PLUS 0x91
|
||||
#define CMD_SAFETY_DOOR 0x84
|
||||
#define CMD_JOG_CANCEL 0x85
|
||||
#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
|
||||
#define CMD_FEED_OVR_RESET 0x90 // Restores feed override value to 100%.
|
||||
#define CMD_FEED_OVR_COARSE_PLUS 0x91
|
||||
#define CMD_FEED_OVR_COARSE_MINUS 0x92
|
||||
#define CMD_FEED_OVR_FINE_PLUS 0x93
|
||||
#define CMD_FEED_OVR_FINE_MINUS 0x94
|
||||
#define CMD_RAPID_OVR_RESET 0x95 // Restores rapid override value to 100%.
|
||||
#define CMD_RAPID_OVR_MEDIUM 0x96
|
||||
#define CMD_RAPID_OVR_LOW 0x97
|
||||
#define CMD_FEED_OVR_FINE_PLUS 0x93
|
||||
#define CMD_FEED_OVR_FINE_MINUS 0x94
|
||||
#define CMD_RAPID_OVR_RESET 0x95 // Restores rapid override value to 100%.
|
||||
#define CMD_RAPID_OVR_MEDIUM 0x96
|
||||
#define CMD_RAPID_OVR_LOW 0x97
|
||||
// #define CMD_RAPID_OVR_EXTRA_LOW 0x98 // *NOT SUPPORTED*
|
||||
#define CMD_SPINDLE_OVR_RESET 0x99 // Restores spindle override value to 100%.
|
||||
#define CMD_SPINDLE_OVR_COARSE_PLUS 0x9A
|
||||
#define CMD_SPINDLE_OVR_RESET 0x99 // Restores spindle override value to 100%.
|
||||
#define CMD_SPINDLE_OVR_COARSE_PLUS 0x9A
|
||||
#define CMD_SPINDLE_OVR_COARSE_MINUS 0x9B
|
||||
#define CMD_SPINDLE_OVR_FINE_PLUS 0x9C
|
||||
#define CMD_SPINDLE_OVR_FINE_MINUS 0x9D
|
||||
#define CMD_SPINDLE_OVR_STOP 0x9E
|
||||
#define CMD_SPINDLE_OVR_FINE_PLUS 0x9C
|
||||
#define CMD_SPINDLE_OVR_FINE_MINUS 0x9D
|
||||
#define CMD_SPINDLE_OVR_STOP 0x9E
|
||||
#define CMD_COOLANT_FLOOD_OVR_TOGGLE 0xA0
|
||||
#define CMD_COOLANT_MIST_OVR_TOGGLE 0xA1
|
||||
#define CMD_COOLANT_MIST_OVR_TOGGLE 0xA1
|
||||
|
||||
// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
|
||||
// the user to perform the homing cycle (or override the locks) before doing anything else. This is
|
||||
|
|
@ -102,12 +101,12 @@
|
|||
// on separate pin, but homed in one cycle. Also, it should be noted that the function of hard limits
|
||||
// will not be affected by pin sharing.
|
||||
// NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y.
|
||||
#define HOMING_CYCLE_0 (1<<Z_AXIS) // REQUIRED: First move Z to clear workspace.
|
||||
#define HOMING_CYCLE_1 ((1<<X_AXIS)|(1<<Y_AXIS)) // OPTIONAL: Then move X,Y at the same time.
|
||||
#define HOMING_CYCLE_0 (1 << Z_AXIS) // REQUIRED: First move Z to clear workspace.
|
||||
#define HOMING_CYCLE_1 ((1 << X_AXIS) | (1 << Y_AXIS)) // OPTIONAL: Then move X,Y at the same time.
|
||||
// #define HOMING_CYCLE_2 // OPTIONAL: Uncomment and add axes mask to enable
|
||||
|
||||
// NOTE: The following are two examples to setup homing for 2-axis machines.
|
||||
// #define HOMING_CYCLE_0 ((1<<X_AXIS)|(1<<Y_AXIS)) // NOT COMPATIBLE WITH COREXY: Homes both X-Y in one cycle.
|
||||
// #define HOMING_CYCLE_0 ((1<<X_AXIS)|(1<<Y_AXIS)) // NOT COMPATIBLE WITH COREXY: Homes both X-Y in one cycle.
|
||||
|
||||
// #define HOMING_CYCLE_0 (1<<X_AXIS) // COREXY COMPATIBLE: First home X
|
||||
// #define HOMING_CYCLE_1 (1<<Y_AXIS) // COREXY COMPATIBLE: Then home Y
|
||||
|
|
@ -117,7 +116,7 @@
|
|||
// greater.
|
||||
#define N_HOMING_LOCATE_CYCLE 1 // Integer (1-128)
|
||||
|
||||
// Enables single axis homing commands. $HX, $HY, and $HZ for X, Y, and Z-axis homing. The full homing
|
||||
// Enables single axis homing commands. $HX, $HY, and $HZ for X, Y, and Z-axis homing. The full homing
|
||||
// cycle is still invoked by the $H command. This is disabled by default. It's here only to address
|
||||
// users that need to switch between a two-axis and three-axis machine. This is actually very rare.
|
||||
// If you have a two-axis machine, DON'T USE THIS. Instead, just alter the homing cycle for two-axes.
|
||||
|
|
@ -238,22 +237,22 @@
|
|||
// Configure rapid, feed, and spindle override settings. These values define the max and min
|
||||
// allowable override values and the coarse and fine increments per command received. Please
|
||||
// note the allowable values in the descriptions following each define.
|
||||
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
|
||||
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
|
||||
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
|
||||
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
|
||||
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
|
||||
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
|
||||
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
|
||||
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
|
||||
// #define RAPID_OVERRIDE_EXTRA_LOW 5 // *NOT SUPPORTED* Percent of rapid (1-99). Usually 5%.
|
||||
|
||||
#define DEFAULT_SPINDLE_SPEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_SPINDLE_SPEED_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
|
||||
#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
// When a M2 or M30 program end command is executed, most g-code states are restored to their defaults.
|
||||
// This compile-time option includes the restoring of the feed, rapid, and spindle speed override values
|
||||
|
|
@ -262,16 +261,16 @@
|
|||
|
||||
// The status report change for Grbl v1.1 and after also removed the ability to disable/enable most data
|
||||
// fields from the report. This caused issues for GUI developers, who've had to manage several scenarios
|
||||
// and configurations. The increased efficiency of the new reporting style allows for all data fields to
|
||||
// and configurations. The increased efficiency of the new reporting style allows for all data fields to
|
||||
// be sent without potential performance issues.
|
||||
// NOTE: The options below are here only provide a way to disable certain data fields if a unique
|
||||
// situation demands it, but be aware GUIs may depend on this data. If disabled, it may not be compatible.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_PIN_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_PIN_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_CURRENT_FEED_SPEED // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_WORK_COORD_OFFSET // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_OVERRIDES // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_LINE_NUMBERS // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_WORK_COORD_OFFSET // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_OVERRIDES // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_LINE_NUMBERS // Default enabled. Comment to disable.
|
||||
|
||||
// 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
|
||||
|
|
@ -282,10 +281,10 @@
|
|||
// refreshes more often when its not doing anything important. With a good GUI, this data doesn't need
|
||||
// to be refreshed very often, on the order of a several seconds.
|
||||
// NOTE: WCO refresh must be 2 or greater. OVR refresh must be 1 or greater.
|
||||
#define REPORT_OVR_REFRESH_BUSY_COUNT 20 // (1-255)
|
||||
#define REPORT_OVR_REFRESH_IDLE_COUNT 10 // (1-255) Must be less than or equal to the busy count
|
||||
#define REPORT_WCO_REFRESH_BUSY_COUNT 30 // (2-255)
|
||||
#define REPORT_WCO_REFRESH_IDLE_COUNT 10 // (2-255) Must be less than or equal to the busy count
|
||||
#define REPORT_OVR_REFRESH_BUSY_COUNT 20 // (1-255)
|
||||
#define REPORT_OVR_REFRESH_IDLE_COUNT 10 // (1-255) Must be less than or equal to the busy count
|
||||
#define REPORT_WCO_REFRESH_BUSY_COUNT 30 // (2-255)
|
||||
#define REPORT_WCO_REFRESH_IDLE_COUNT 10 // (2-255) Must be less than or equal to the busy count
|
||||
|
||||
// The temporal resolution of the acceleration management subsystem. A higher number gives smoother
|
||||
// acceleration, particularly noticeable on machines that run at very high feedrates, but may negatively
|
||||
|
|
@ -301,7 +300,7 @@
|
|||
// frequencies below 10kHz, where the aliasing between axes of multi-axis motions can cause audible
|
||||
// noise and shake your machine. At even lower step frequencies, AMASS adapts and provides even better
|
||||
// step smoothing. See stepper.c for more details on the AMASS system works.
|
||||
#define ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING // Default enabled. Comment to disable.
|
||||
#define ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING // Default enabled. Comment to disable.
|
||||
|
||||
// Sets the maximum step rate allowed to be written as a Grbl setting. This option enables an error
|
||||
// check in the settings module to prevent settings values that will exceed this limitation. The maximum
|
||||
|
|
@ -323,9 +322,9 @@
|
|||
// normal-open switch and vice versa.
|
||||
// NOTE: All pins associated with the feature are disabled, i.e. XYZ limit pins, not individual axes.
|
||||
// WARNING: When the pull-ups are disabled, this requires additional wiring with pull-down resistors!
|
||||
//#define DISABLE_LIMIT_PIN_PULL_UP
|
||||
//#define DISABLE_PROBE_PIN_PULL_UP
|
||||
//#define DISABLE_CONTROL_PIN_PULL_UP
|
||||
// #define DISABLE_LIMIT_PIN_PULL_UP
|
||||
// #define DISABLE_PROBE_PIN_PULL_UP
|
||||
// #define DISABLE_CONTROL_PIN_PULL_UP
|
||||
|
||||
// Sets which axis the tool length offset is applied. Assumes the spindle is always parallel with
|
||||
// the selected axis with the tool oriented toward the negative direction. In other words, a positive
|
||||
|
|
@ -353,16 +352,16 @@
|
|||
// preserve I/O pins. For certain setups, these may need to be separate pins. This configure option uses
|
||||
// the spindle direction pin(D13) as a separate spindle enable pin along with spindle speed PWM on pin D11.
|
||||
// NOTE: This configure option only works with VARIABLE_SPINDLE enabled and a 328p processor (Uno).
|
||||
// NOTE: Without a direction pin, M4 will not have a pin output to indicate a difference with M3.
|
||||
// NOTE: Without a direction pin, M4 will not have a pin output to indicate a difference with M3.
|
||||
// NOTE: BEWARE! The Arduino bootloader toggles the D13 pin when it powers up. If you flash Grbl with
|
||||
// a programmer (you can use a spare Arduino as "Arduino as ISP". Search the web on how to wire this.),
|
||||
// this D13 LED toggling should go away. We haven't tested this though. Please report how it goes!
|
||||
// #define USE_SPINDLE_DIR_AS_ENABLE_PIN // Default disabled. Uncomment to enable.
|
||||
|
||||
// Alters the behavior of the spindle enable pin with the USE_SPINDLE_DIR_AS_ENABLE_PIN option . By default,
|
||||
// Grbl will not disable the enable pin if spindle speed is zero and M3/4 is active, but still sets the PWM
|
||||
// Grbl will not disable the enable pin if spindle speed is zero and M3/4 is active, but still sets the PWM
|
||||
// output to zero. This allows the users to know if the spindle is active and use it as an additional control
|
||||
// input. However, in some use cases, user may want the enable pin to disable with a zero spindle speed and
|
||||
// input. However, in some use cases, user may want the enable pin to disable with a zero spindle speed and
|
||||
// re-enable when spindle speed is greater than zero. This option does that.
|
||||
// NOTE: Requires USE_SPINDLE_DIR_AS_ENABLE_PIN to be enabled.
|
||||
// #define SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED // Default disabled. Uncomment to enable.
|
||||
|
|
@ -462,12 +461,12 @@
|
|||
// #define RX_BUFFER_SIZE 128 // (1-254) Uncomment to override defaults in serial.h
|
||||
// #define TX_BUFFER_SIZE 100 // (1-254)
|
||||
|
||||
// A simple software debouncing feature for hard limit switches. When enabled, the interrupt
|
||||
// monitoring the hard limit switch pins will enable the Arduino's watchdog timer to re-check
|
||||
// the limit pin state after a delay of about 32msec. This can help with CNC machines with
|
||||
// problematic false triggering of their hard limit switches, but it WILL NOT fix issues with
|
||||
// A simple software debouncing feature for hard limit switches. When enabled, the interrupt
|
||||
// monitoring the hard limit switch pins will enable the Arduino's watchdog timer to re-check
|
||||
// the limit pin state after a delay of about 32msec. This can help with CNC machines with
|
||||
// problematic false triggering of their hard limit switches, but it WILL NOT fix issues with
|
||||
// electrical interference on the signal cables from external sources. It's recommended to first
|
||||
// use shielded signal cables with their shielding connected to ground (old USB/computer cables
|
||||
// use shielded signal cables with their shielding connected to ground (old USB/computer cables
|
||||
// work well and are cheap to find) and wire in a low-pass circuit into each limit pin.
|
||||
// #define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
|
||||
|
|
@ -509,7 +508,8 @@
|
|||
// written into the Arduino EEPROM via a seperate .INO sketch to contain product data. Altering this
|
||||
// macro to not restore the build info EEPROM will ensure this data is retained after firmware upgrades.
|
||||
// NOTE: Uncomment to override defaults in settings.h
|
||||
// #define SETTINGS_RESTORE_ALL (SETTINGS_RESTORE_DEFAULTS | SETTINGS_RESTORE_PARAMETERS | SETTINGS_RESTORE_STARTUP_LINES | SETTINGS_RESTORE_BUILD_INFO)
|
||||
// #define SETTINGS_RESTORE_ALL (SETTINGS_RESTORE_DEFAULTS | SETTINGS_RESTORE_PARAMETERS |
|
||||
// SETTINGS_RESTORE_STARTUP_LINES | SETTINGS_RESTORE_BUILD_INFO)
|
||||
|
||||
// Enable the '$I=(string)' build info write command. If disabled, any existing build info data must
|
||||
// be placed into EEPROM via external means with a valid checksum value. This macro option is useful
|
||||
|
|
@ -542,8 +542,8 @@
|
|||
#define FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // Default enabled. Comment to disable.
|
||||
|
||||
// By default, Grbl disables feed rate overrides for all G38.x probe cycle commands. Although this
|
||||
// may be different than some pro-class machine control, it's arguable that it should be this way.
|
||||
// Most probe sensors produce different levels of error that is dependent on rate of speed. By
|
||||
// may be different than some pro-class machine control, it's arguable that it should be this way.
|
||||
// Most probe sensors produce different levels of error that is dependent on rate of speed. By
|
||||
// keeping probing cycles to their programmed feed rates, the probe sensor should be a lot more
|
||||
// repeatable. If needed, you can disable this behavior by uncommenting the define below.
|
||||
// #define ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES // Default disabled. Uncomment to enable.
|
||||
|
|
@ -564,18 +564,19 @@
|
|||
// #define PARKING_ENABLE // Default disabled. Uncomment to enable
|
||||
|
||||
// Configure options for the parking motion, if enabled.
|
||||
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
|
||||
#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
|
||||
#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
|
||||
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
|
||||
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
// Must be positive value or equal to zero.
|
||||
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
|
||||
#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
|
||||
#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
|
||||
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
|
||||
#define PARKING_PULLOUT_INCREMENT \
|
||||
5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
// Must be positive value or equal to zero.
|
||||
|
||||
// Enables a special set of M-code commands that enables and disables the parking motion.
|
||||
// These are controlled by `M56`, `M56 P1`, or `M56 Px` to enable and `M56 P0` to disable.
|
||||
// The command is modal and will be set after a planner sync. Since it is g-code, it is
|
||||
// Enables a special set of M-code commands that enables and disables the parking motion.
|
||||
// These are controlled by `M56`, `M56 P1`, or `M56 Px` to enable and `M56 P0` to disable.
|
||||
// The command is modal and will be set after a planner sync. Since it is g-code, it is
|
||||
// executed in sync with g-code commands. It is not a real-time command.
|
||||
// NOTE: PARKING_ENABLE is required. By default, M56 is active upon initialization. Use
|
||||
// NOTE: PARKING_ENABLE is required. By default, M56 is active upon initialization. Use
|
||||
// DEACTIVATE_PARKING_UPON_INIT to set M56 P0 as the power-up default.
|
||||
// #define ENABLE_PARKING_OVERRIDE_CONTROL // Default disabled. Uncomment to enable
|
||||
// #define DEACTIVATE_PARKING_UPON_INIT // Default disabled. Uncomment to enable.
|
||||
|
|
@ -587,7 +588,7 @@
|
|||
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
|
||||
|
||||
// This feature alters the spindle PWM/speed to a nonlinear output with a simple piecewise linear
|
||||
// curve. Useful for spindles that don't produce the right RPM from Grbl's standard spindle PWM
|
||||
// curve. Useful for spindles that don't produce the right RPM from Grbl's standard spindle PWM
|
||||
// linear model. Requires a solution by the 'fit_nonlinear_spindle.py' script in the /doc/script
|
||||
// folder of the repo. See file comments on how to gather spindle data and run the script to
|
||||
// generate a solution.
|
||||
|
|
@ -597,41 +598,41 @@
|
|||
// the 'fit_nonlinear_spindle.py' script solution. Used only when ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
// is enabled. Make sure the constant values are exactly the same as the script solution.
|
||||
// NOTE: When N_PIECES < 4, unused RPM_LINE and RPM_POINT defines are not required and omitted.
|
||||
#define N_PIECES 4 // Integer (1-4). Number of piecewise lines used in script solution.
|
||||
#define RPM_MAX 11686.4 // Max RPM of model. $30 > RPM_MAX will be limited to RPM_MAX.
|
||||
#define RPM_MIN 202.5 // Min RPM of model. $31 < RPM_MIN will be limited to RPM_MIN.
|
||||
#define RPM_POINT12 6145.4 // Used N_PIECES >=2. Junction point between lines 1 and 2.
|
||||
#define RPM_POINT23 9627.8 // Used N_PIECES >=3. Junction point between lines 2 and 3.
|
||||
#define RPM_POINT34 10813.9 // Used N_PIECES = 4. Junction point between lines 3 and 4.
|
||||
#define RPM_LINE_A1 3.197101e-03 // Used N_PIECES >=1. A and B constants of line 1.
|
||||
#define RPM_LINE_B1 -3.526076e-1
|
||||
#define RPM_LINE_A2 1.722950e-2 // Used N_PIECES >=2. A and B constants of line 2.
|
||||
#define RPM_LINE_B2 8.588176e+01
|
||||
#define RPM_LINE_A3 5.901518e-02 // Used N_PIECES >=3. A and B constants of line 3.
|
||||
#define RPM_LINE_B3 4.881851e+02
|
||||
#define RPM_LINE_A4 1.203413e-01 // Used N_PIECES = 4. A and B constants of line 4.
|
||||
#define RPM_LINE_B4 1.151360e+03
|
||||
#define N_PIECES 4 // Integer (1-4). Number of piecewise lines used in script solution.
|
||||
#define RPM_MAX 11686.4 // Max RPM of model. $30 > RPM_MAX will be limited to RPM_MAX.
|
||||
#define RPM_MIN 202.5 // Min RPM of model. $31 < RPM_MIN will be limited to RPM_MIN.
|
||||
#define RPM_POINT12 6145.4 // Used N_PIECES >=2. Junction point between lines 1 and 2.
|
||||
#define RPM_POINT23 9627.8 // Used N_PIECES >=3. Junction point between lines 2 and 3.
|
||||
#define RPM_POINT34 10813.9 // Used N_PIECES = 4. Junction point between lines 3 and 4.
|
||||
#define RPM_LINE_A1 3.197101e-03 // Used N_PIECES >=1. A and B constants of line 1.
|
||||
#define RPM_LINE_B1 -3.526076e-1
|
||||
#define RPM_LINE_A2 1.722950e-2 // Used N_PIECES >=2. A and B constants of line 2.
|
||||
#define RPM_LINE_B2 8.588176e+01
|
||||
#define RPM_LINE_A3 5.901518e-02 // Used N_PIECES >=3. A and B constants of line 3.
|
||||
#define RPM_LINE_B3 4.881851e+02
|
||||
#define RPM_LINE_A4 1.203413e-01 // Used N_PIECES = 4. A and B constants of line 4.
|
||||
#define RPM_LINE_B4 1.151360e+03
|
||||
|
||||
/* ---------------------------------------------------------------------------------------
|
||||
This optional dual axis feature is primarily for the homing cycle to locate two sides of
|
||||
/* ---------------------------------------------------------------------------------------
|
||||
This optional dual axis feature is primarily for the homing cycle to locate two sides of
|
||||
a dual-motor gantry independently, i.e. self-squaring. This requires an additional limit
|
||||
switch for the cloned motor. To self square, both limit switches on the cloned axis must
|
||||
be physically positioned to trigger when the gantry is square. Highly recommend keeping
|
||||
be physically positioned to trigger when the gantry is square. Highly recommend keeping
|
||||
the motors always enabled to ensure the gantry stays square with the $1=255 setting.
|
||||
|
||||
For Grbl on the Arduino Uno, the cloned axis limit switch must to be shared with and
|
||||
For Grbl on the Arduino Uno, the cloned axis limit switch must to be shared with and
|
||||
wired with z-axis limit pin due to the lack of available pins. The homing cycle must home
|
||||
the z-axis and cloned axis in different cycles, which is already the default config.
|
||||
|
||||
The dual axis feature works by cloning an axis step output onto another pair of step
|
||||
and direction pins. The step pulse and direction of the cloned motor can be set
|
||||
and direction pins. The step pulse and direction of the cloned motor can be set
|
||||
independently of the main axis motor. However to save precious flash and memory, this
|
||||
dual axis feature must share the same settings (step/mm, max speed, acceleration) as the
|
||||
dual axis feature must share the same settings (step/mm, max speed, acceleration) as the
|
||||
parent motor. This is NOT a feature for an independent fourth axis. Only a motor clone.
|
||||
|
||||
WARNING: Make sure to test the directions of your dual axis motors! They must be setup
|
||||
to move the same direction BEFORE running your first homing cycle or any long motion!
|
||||
Motors moving in opposite directions can cause serious damage to your machine! Use this
|
||||
Motors moving in opposite directions can cause serious damage to your machine! Use this
|
||||
dual axis feature at your own risk.
|
||||
*/
|
||||
// NOTE: This feature requires approximately 400 bytes of flash. Certain configurations can
|
||||
|
|
@ -641,40 +642,39 @@
|
|||
// #define ENABLE_DUAL_AXIS // Default disabled. Uncomment to enable.
|
||||
|
||||
// Select the one axis to mirror another motor. Only X and Y axis is supported at this time.
|
||||
#define DUAL_AXIS_SELECT X_AXIS // Must be either X_AXIS or Y_AXIS
|
||||
#define DUAL_AXIS_SELECT X_AXIS // Must be either X_AXIS or Y_AXIS
|
||||
|
||||
// To prevent the homing cycle from racking the dual axis, when one limit triggers before the
|
||||
// other due to switch failure or noise, the homing cycle will automatically abort if the second
|
||||
// motor's limit switch does not trigger within the three distance parameters defined below.
|
||||
// other due to switch failure or noise, the homing cycle will automatically abort if the second
|
||||
// motor's limit switch does not trigger within the three distance parameters defined below.
|
||||
// Axis length percent will automatically compute a fail distance as a percentage of the max
|
||||
// travel of the other non-dual axis, i.e. if dual axis select is X_AXIS at 5.0%, then the fail
|
||||
// distance will be computed as 5.0% of y-axis max travel. Fail distance max and min are the
|
||||
// travel of the other non-dual axis, i.e. if dual axis select is X_AXIS at 5.0%, then the fail
|
||||
// distance will be computed as 5.0% of y-axis max travel. Fail distance max and min are the
|
||||
// limits of how far or little a valid fail distance is.
|
||||
#define DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT 5.0 // Float (percent)
|
||||
#define DUAL_AXIS_HOMING_FAIL_DISTANCE_MAX 25.0 // Float (mm)
|
||||
#define DUAL_AXIS_HOMING_FAIL_DISTANCE_MIN 2.5 // Float (mm)
|
||||
#define DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT 5.0 // Float (percent)
|
||||
#define DUAL_AXIS_HOMING_FAIL_DISTANCE_MAX 25.0 // Float (mm)
|
||||
#define DUAL_AXIS_HOMING_FAIL_DISTANCE_MIN 2.5 // Float (mm)
|
||||
|
||||
// Dual axis pin configuration currently supports two shields. Uncomment the shield you want,
|
||||
// and comment out the other one(s).
|
||||
// NOTE: Protoneer CNC Shield v3.51 has A.STP and A.DIR wired to pins A4 and A3 respectively.
|
||||
// The variable spindle (i.e. laser mode) build option works and may be enabled or disabled.
|
||||
// Coolant pin A3 is moved to D13, replacing spindle direction.
|
||||
#define DUAL_AXIS_CONFIG_PROTONEER_V3_51 // Uncomment to select. Comment other configs.
|
||||
#define DUAL_AXIS_CONFIG_PROTONEER_V3_51 // Uncomment to select. Comment other configs.
|
||||
|
||||
// NOTE: Arduino CNC Shield Clone (Originally Protoneer v3.0) has A.STP and A.DIR wired to
|
||||
// NOTE: Arduino CNC Shield Clone (Originally Protoneer v3.0) has A.STP and A.DIR wired to
|
||||
// D12 and D13, respectively. With the limit pins and stepper enable pin on this same port,
|
||||
// the spindle enable pin had to be moved and spindle direction pin deleted. The spindle
|
||||
// enable pin now resides on A3, replacing coolant enable. Coolant enable is bumped over to
|
||||
// pin A4. Spindle enable is used far more and this pin setup helps facilitate users to
|
||||
// integrate this feature without arguably too much work.
|
||||
// pin A4. Spindle enable is used far more and this pin setup helps facilitate users to
|
||||
// integrate this feature without arguably too much work.
|
||||
// Variable spindle (i.e. laser mode) does NOT work with this shield as configured. While
|
||||
// variable spindle technically can work with this shield, it requires too many changes for
|
||||
// most user setups to accomodate. It would best be implemented by sharing all limit switches
|
||||
// on pins D9/D10 (as [X1,Z]/[X2,Y] or [X,Y2]/[Y1,Z]), home each axis independently, and
|
||||
// on pins D9/D10 (as [X1,Z]/[X2,Y] or [X,Y2]/[Y1,Z]), home each axis independently, and
|
||||
// updating lots of code to ensure everything is running correctly.
|
||||
// #define DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE // Uncomment to select. Comment other configs.
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------
|
||||
OEM Single File Configuration Option
|
||||
|
||||
|
|
@ -688,5 +688,4 @@
|
|||
|
||||
// Paste default settings definitions here.
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,107 +20,101 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
void coolant_init()
|
||||
{
|
||||
COOLANT_FLOOD_DDR |= (1 << COOLANT_FLOOD_BIT); // Configure as output pin
|
||||
#ifdef ENABLE_M7
|
||||
void coolant_init() {
|
||||
COOLANT_FLOOD_DDR |= (1 << COOLANT_FLOOD_BIT); // Configure as output pin
|
||||
#ifdef ENABLE_M7
|
||||
COOLANT_MIST_DDR |= (1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
coolant_stop();
|
||||
#endif
|
||||
coolant_stop();
|
||||
}
|
||||
|
||||
|
||||
// Returns current coolant output state. Overrides may alter it from programmed state.
|
||||
uint8_t coolant_get_state()
|
||||
{
|
||||
uint8_t cl_state = COOLANT_STATE_DISABLE;
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
if (bit_isfalse(COOLANT_FLOOD_PORT,(1 << COOLANT_FLOOD_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(COOLANT_FLOOD_PORT,(1 << COOLANT_FLOOD_BIT))) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_FLOOD;
|
||||
}
|
||||
#ifdef ENABLE_M7
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
if (bit_isfalse(COOLANT_MIST_PORT,(1 << COOLANT_MIST_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(COOLANT_MIST_PORT,(1 << COOLANT_MIST_BIT))) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_MIST;
|
||||
uint8_t coolant_get_state() {
|
||||
uint8_t cl_state = COOLANT_STATE_DISABLE;
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
if (bit_isfalse(COOLANT_FLOOD_PORT, (1 << COOLANT_FLOOD_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(COOLANT_FLOOD_PORT, (1 << COOLANT_FLOOD_BIT))) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_FLOOD;
|
||||
}
|
||||
#endif
|
||||
return(cl_state);
|
||||
#ifdef ENABLE_M7
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
if (bit_isfalse(COOLANT_MIST_PORT, (1 << COOLANT_MIST_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(COOLANT_MIST_PORT, (1 << COOLANT_MIST_BIT))) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_MIST;
|
||||
}
|
||||
#endif
|
||||
return (cl_state);
|
||||
}
|
||||
|
||||
|
||||
// Directly called by coolant_init(), coolant_set_state(), and mc_reset(), which can be at
|
||||
// an interrupt-level. No report flag set, but only called by routines that don't need it.
|
||||
void coolant_stop()
|
||||
{
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
void coolant_stop() {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
|
||||
#else
|
||||
#else
|
||||
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
|
||||
#endif
|
||||
#ifdef ENABLE_M7
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef ENABLE_M7
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Main program only. Immediately sets flood coolant running state and also mist coolant,
|
||||
// Main program only. Immediately sets flood coolant running state and also mist coolant,
|
||||
// if enabled. Also sets a flag to report an update to a coolant state.
|
||||
// Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code
|
||||
// parser program end, and g-code parser coolant_sync().
|
||||
void coolant_set_state(uint8_t mode)
|
||||
{
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
|
||||
if (mode & COOLANT_FLOOD_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
|
||||
#else
|
||||
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
|
||||
#else
|
||||
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_M7
|
||||
if (mode & COOLANT_MIST_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
void coolant_set_state(uint8_t mode) {
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Block during abort.
|
||||
|
||||
if (mode & COOLANT_FLOOD_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
|
||||
#else
|
||||
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
COOLANT_FLOOD_PORT |= (1 << COOLANT_FLOOD_BIT);
|
||||
#else
|
||||
COOLANT_FLOOD_PORT &= ~(1 << COOLANT_FLOOD_BIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_M7
|
||||
if (mode & COOLANT_MIST_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
COOLANT_MIST_PORT |= (1 << COOLANT_MIST_BIT);
|
||||
#else
|
||||
COOLANT_MIST_PORT &= ~(1 << COOLANT_MIST_BIT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
|
||||
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
|
||||
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
|
||||
// if an abort or check-mode is active.
|
||||
void coolant_sync(uint8_t mode)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
|
||||
coolant_set_state(mode);
|
||||
void coolant_sync(uint8_t mode) {
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
|
||||
coolant_set_state(mode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,12 @@
|
|||
#ifndef coolant_control_h
|
||||
#define coolant_control_h
|
||||
|
||||
#define COOLANT_NO_SYNC false
|
||||
#define COOLANT_FORCE_SYNC true
|
||||
|
||||
#define COOLANT_STATE_DISABLE 0 // Must be zero
|
||||
#define COOLANT_STATE_FLOOD PL_COND_FLAG_COOLANT_FLOOD
|
||||
#define COOLANT_STATE_MIST PL_COND_FLAG_COOLANT_MIST
|
||||
#define COOLANT_NO_SYNC false
|
||||
#define COOLANT_FORCE_SYNC true
|
||||
|
||||
#define COOLANT_STATE_DISABLE 0 // Must be zero
|
||||
#define COOLANT_STATE_FLOOD PL_COND_FLAG_COOLANT_FLOOD
|
||||
#define COOLANT_STATE_MIST PL_COND_FLAG_COOLANT_MIST
|
||||
|
||||
// Initializes coolant control pins.
|
||||
void coolant_init();
|
||||
|
|
|
|||
389
grbl/cpu_map.h
389
grbl/cpu_map.h
|
|
@ -22,230 +22,231 @@
|
|||
processor types or alternative pin layouts. This version of Grbl officially supports
|
||||
only the Arduino Mega328p. */
|
||||
|
||||
|
||||
#ifndef cpu_map_h
|
||||
#define cpu_map_h
|
||||
|
||||
|
||||
#ifdef CPU_MAP_ATMEGA328P // (Arduino Uno) Officially supported by Grbl.
|
||||
|
||||
// Define serial port pins and interrupt vectors.
|
||||
#define SERIAL_RX USART_RX_vect
|
||||
#define SERIAL_UDRE USART_UDRE_vect
|
||||
// Define serial port pins and interrupt vectors.
|
||||
#define SERIAL_RX USART_RX_vect
|
||||
#define SERIAL_UDRE USART_UDRE_vect
|
||||
|
||||
// Define step pulse output pins. NOTE: All step bit pins must be on the same port.
|
||||
#define STEP_DDR DDRD
|
||||
#define STEP_PORT PORTD
|
||||
#define X_STEP_BIT 2 // Uno Digital Pin 2
|
||||
#define Y_STEP_BIT 3 // Uno Digital Pin 3
|
||||
#define Z_STEP_BIT 4 // Uno Digital Pin 4
|
||||
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
|
||||
// Define step pulse output pins. NOTE: All step bit pins must be on the same port.
|
||||
#define STEP_DDR DDRD
|
||||
#define STEP_PORT PORTD
|
||||
#define X_STEP_BIT 2 // Uno Digital Pin 2
|
||||
#define Y_STEP_BIT 3 // Uno Digital Pin 3
|
||||
#define Z_STEP_BIT 4 // Uno Digital Pin 4
|
||||
#define STEP_MASK ((1 << X_STEP_BIT) | (1 << Y_STEP_BIT) | (1 << Z_STEP_BIT)) // All step bits
|
||||
|
||||
// Define step direction output pins. NOTE: All direction pins must be on the same port.
|
||||
#define DIRECTION_DDR DDRD
|
||||
#define DIRECTION_PORT PORTD
|
||||
#define X_DIRECTION_BIT 5 // Uno Digital Pin 5
|
||||
#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
|
||||
#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
|
||||
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits
|
||||
// Define step direction output pins. NOTE: All direction pins must be on the same port.
|
||||
#define DIRECTION_DDR DDRD
|
||||
#define DIRECTION_PORT PORTD
|
||||
#define X_DIRECTION_BIT 5 // Uno Digital Pin 5
|
||||
#define Y_DIRECTION_BIT 6 // Uno Digital Pin 6
|
||||
#define Z_DIRECTION_BIT 7 // Uno Digital Pin 7
|
||||
#define DIRECTION_MASK ((1 << X_DIRECTION_BIT) | (1 << Y_DIRECTION_BIT) | (1 << Z_DIRECTION_BIT)) // All direction bits
|
||||
|
||||
// Define stepper driver enable/disable output pin.
|
||||
#define STEPPERS_DISABLE_DDR DDRB
|
||||
#define STEPPERS_DISABLE_PORT PORTB
|
||||
#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8
|
||||
#define STEPPERS_DISABLE_MASK (1<<STEPPERS_DISABLE_BIT)
|
||||
// Define stepper driver enable/disable output pin.
|
||||
#define STEPPERS_DISABLE_DDR DDRB
|
||||
#define STEPPERS_DISABLE_PORT PORTB
|
||||
#define STEPPERS_DISABLE_BIT 0 // Uno Digital Pin 8
|
||||
#define STEPPERS_DISABLE_MASK (1 << STEPPERS_DISABLE_BIT)
|
||||
|
||||
// Define homing/hard limit switch input pins and limit interrupt vectors.
|
||||
// NOTE: All limit bit pins must be on the same port, but not on a port with other input pins (CONTROL).
|
||||
#define LIMIT_DDR DDRB
|
||||
#define LIMIT_PIN PINB
|
||||
#define LIMIT_PORT PORTB
|
||||
#define X_LIMIT_BIT 1 // Uno Digital Pin 9
|
||||
#define Y_LIMIT_BIT 2 // Uno Digital Pin 10
|
||||
#ifdef VARIABLE_SPINDLE // Z Limit pin and spindle enabled swapped to access hardware PWM on Pin 11.
|
||||
#define Z_LIMIT_BIT 4 // Uno Digital Pin 12
|
||||
#else
|
||||
#define Z_LIMIT_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
#if !defined(ENABLE_DUAL_AXIS)
|
||||
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)) // All limit bits
|
||||
#endif
|
||||
#define LIMIT_INT PCIE0 // Pin change interrupt enable pin
|
||||
#define LIMIT_INT_vect PCINT0_vect
|
||||
#define LIMIT_PCMSK PCMSK0 // Pin change interrupt register
|
||||
// Define homing/hard limit switch input pins and limit interrupt vectors.
|
||||
// NOTE: All limit bit pins must be on the same port, but not on a port with other input pins (CONTROL).
|
||||
#define LIMIT_DDR DDRB
|
||||
#define LIMIT_PIN PINB
|
||||
#define LIMIT_PORT PORTB
|
||||
#define X_LIMIT_BIT 1 // Uno Digital Pin 9
|
||||
#define Y_LIMIT_BIT 2 // Uno Digital Pin 10
|
||||
#ifdef VARIABLE_SPINDLE // Z Limit pin and spindle enabled swapped to access hardware PWM on Pin 11.
|
||||
#define Z_LIMIT_BIT 4 // Uno Digital Pin 12
|
||||
#else
|
||||
#define Z_LIMIT_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
#if !defined(ENABLE_DUAL_AXIS)
|
||||
#define LIMIT_MASK ((1 << X_LIMIT_BIT) | (1 << Y_LIMIT_BIT) | (1 << Z_LIMIT_BIT)) // All limit bits
|
||||
#endif
|
||||
#define LIMIT_INT PCIE0 // Pin change interrupt enable pin
|
||||
#define LIMIT_INT_vect PCINT0_vect
|
||||
#define LIMIT_PCMSK PCMSK0 // Pin change interrupt register
|
||||
|
||||
// Define user-control controls (cycle start, reset, feed hold) input pins.
|
||||
// NOTE: All CONTROLs pins must be on the same port and not on a port with other input pins (limits).
|
||||
#define CONTROL_DDR DDRC
|
||||
#define CONTROL_PIN PINC
|
||||
#define CONTROL_PORT PORTC
|
||||
#define CONTROL_RESET_BIT 0 // Uno Analog Pin 0
|
||||
#define CONTROL_FEED_HOLD_BIT 1 // Uno Analog Pin 1
|
||||
#define CONTROL_CYCLE_START_BIT 2 // Uno Analog Pin 2
|
||||
#define CONTROL_SAFETY_DOOR_BIT 1 // Uno Analog Pin 1 NOTE: Safety door is shared with feed hold. Enabled by config define.
|
||||
#define CONTROL_INT PCIE1 // Pin change interrupt enable pin
|
||||
#define CONTROL_INT_vect PCINT1_vect
|
||||
#define CONTROL_PCMSK PCMSK1 // Pin change interrupt register
|
||||
#define CONTROL_MASK ((1<<CONTROL_RESET_BIT)|(1<<CONTROL_FEED_HOLD_BIT)|(1<<CONTROL_CYCLE_START_BIT)|(1<<CONTROL_SAFETY_DOOR_BIT))
|
||||
#define CONTROL_INVERT_MASK CONTROL_MASK // May be re-defined to only invert certain control pins.
|
||||
// Define user-control controls (cycle start, reset, feed hold) input pins.
|
||||
// NOTE: All CONTROLs pins must be on the same port and not on a port with other input pins (limits).
|
||||
#define CONTROL_DDR DDRC
|
||||
#define CONTROL_PIN PINC
|
||||
#define CONTROL_PORT PORTC
|
||||
#define CONTROL_RESET_BIT 0 // Uno Analog Pin 0
|
||||
#define CONTROL_FEED_HOLD_BIT 1 // Uno Analog Pin 1
|
||||
#define CONTROL_CYCLE_START_BIT 2 // Uno Analog Pin 2
|
||||
#define CONTROL_SAFETY_DOOR_BIT \
|
||||
1 // Uno Analog Pin 1 NOTE: Safety door is shared with feed hold. Enabled by config define.
|
||||
#define CONTROL_INT PCIE1 // Pin change interrupt enable pin
|
||||
#define CONTROL_INT_vect PCINT1_vect
|
||||
#define CONTROL_PCMSK PCMSK1 // Pin change interrupt register
|
||||
#define CONTROL_MASK \
|
||||
((1 << CONTROL_RESET_BIT) | (1 << CONTROL_FEED_HOLD_BIT) | (1 << CONTROL_CYCLE_START_BIT) | \
|
||||
(1 << CONTROL_SAFETY_DOOR_BIT))
|
||||
#define CONTROL_INVERT_MASK CONTROL_MASK // May be re-defined to only invert certain control pins.
|
||||
|
||||
// Define probe switch input pin.
|
||||
#define PROBE_DDR DDRC
|
||||
#define PROBE_PIN PINC
|
||||
#define PROBE_PORT PORTC
|
||||
#define PROBE_BIT 5 // Uno Analog Pin 5
|
||||
#define PROBE_MASK (1<<PROBE_BIT)
|
||||
// Define probe switch input pin.
|
||||
#define PROBE_DDR DDRC
|
||||
#define PROBE_PIN PINC
|
||||
#define PROBE_PORT PORTC
|
||||
#define PROBE_BIT 5 // Uno Analog Pin 5
|
||||
#define PROBE_MASK (1 << PROBE_BIT)
|
||||
|
||||
#if !defined(ENABLE_DUAL_AXIS)
|
||||
#if !defined(ENABLE_DUAL_AXIS)
|
||||
|
||||
// Define flood and mist coolant enable output pins.
|
||||
#define COOLANT_FLOOD_DDR DDRC
|
||||
#define COOLANT_FLOOD_PORT PORTC
|
||||
#define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3
|
||||
#define COOLANT_MIST_DDR DDRC
|
||||
#define COOLANT_MIST_PORT PORTC
|
||||
#define COOLANT_MIST_BIT 4 // Uno Analog Pin 4
|
||||
// Define flood and mist coolant enable output pins.
|
||||
#define COOLANT_FLOOD_DDR DDRC
|
||||
#define COOLANT_FLOOD_PORT PORTC
|
||||
#define COOLANT_FLOOD_BIT 3 // Uno Analog Pin 3
|
||||
#define COOLANT_MIST_DDR DDRC
|
||||
#define COOLANT_MIST_PORT PORTC
|
||||
#define COOLANT_MIST_BIT 4 // Uno Analog Pin 4
|
||||
|
||||
// Define spindle enable and spindle direction output pins.
|
||||
#define SPINDLE_ENABLE_DDR DDRB
|
||||
#define SPINDLE_ENABLE_PORT PORTB
|
||||
// Z Limit pin and spindle PWM/enable pin swapped to access hardware PWM on Pin 11.
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
// If enabled, spindle direction pin now used as spindle enable, while PWM remains on D11.
|
||||
#define SPINDLE_ENABLE_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
|
||||
#endif
|
||||
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
#define SPINDLE_DIRECTION_DDR DDRB
|
||||
#define SPINDLE_DIRECTION_PORT PORTB
|
||||
#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
|
||||
#endif
|
||||
// Define spindle enable and spindle direction output pins.
|
||||
#define SPINDLE_ENABLE_DDR DDRB
|
||||
#define SPINDLE_ENABLE_PORT PORTB
|
||||
// Z Limit pin and spindle PWM/enable pin swapped to access hardware PWM on Pin 11.
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
// If enabled, spindle direction pin now used as spindle enable, while PWM remains on D11.
|
||||
#define SPINDLE_ENABLE_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
|
||||
#endif
|
||||
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
#define SPINDLE_DIRECTION_DDR DDRB
|
||||
#define SPINDLE_DIRECTION_PORT PORTB
|
||||
#define SPINDLE_DIRECTION_BIT 5 // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
|
||||
#endif
|
||||
|
||||
// Variable spindle configuration below. Do not change unless you know what you are doing.
|
||||
// NOTE: Only used when variable spindle is enabled.
|
||||
#define SPINDLE_PWM_MAX_VALUE 255 // Don't change. 328p fast PWM mode fixes top value as 255.
|
||||
#ifndef SPINDLE_PWM_MIN_VALUE
|
||||
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
|
||||
#endif
|
||||
#define SPINDLE_PWM_OFF_VALUE 0
|
||||
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)
|
||||
#define SPINDLE_TCCRA_REGISTER TCCR2A
|
||||
#define SPINDLE_TCCRB_REGISTER TCCR2B
|
||||
#define SPINDLE_OCR_REGISTER OCR2A
|
||||
#define SPINDLE_COMB_BIT COM2A1
|
||||
// Variable spindle configuration below. Do not change unless you know what you are doing.
|
||||
// NOTE: Only used when variable spindle is enabled.
|
||||
#define SPINDLE_PWM_MAX_VALUE 255 // Don't change. 328p fast PWM mode fixes top value as 255.
|
||||
#ifndef SPINDLE_PWM_MIN_VALUE
|
||||
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
|
||||
#endif
|
||||
#define SPINDLE_PWM_OFF_VALUE 0
|
||||
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE - SPINDLE_PWM_MIN_VALUE)
|
||||
#define SPINDLE_TCCRA_REGISTER TCCR2A
|
||||
#define SPINDLE_TCCRB_REGISTER TCCR2B
|
||||
#define SPINDLE_OCR_REGISTER OCR2A
|
||||
#define SPINDLE_COMB_BIT COM2A1
|
||||
|
||||
// Prescaled, 8-bit Fast PWM mode.
|
||||
#define SPINDLE_TCCRA_INIT_MASK ((1<<WGM20) | (1<<WGM21)) // Configures fast PWM mode.
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS20) // Disable prescaler -> 62.5kHz
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS21) // 1/8 prescaler -> 7.8kHz (Used in v0.9)
|
||||
// #define SPINDLE_TCCRB_INIT_MASK ((1<<CS21) | (1<<CS20)) // 1/32 prescaler -> 1.96kHz
|
||||
#define SPINDLE_TCCRB_INIT_MASK (1<<CS22) // 1/64 prescaler -> 0.98kHz (J-tech laser)
|
||||
// Prescaled, 8-bit Fast PWM mode.
|
||||
#define SPINDLE_TCCRA_INIT_MASK ((1 << WGM20) | (1 << WGM21)) // Configures fast PWM mode.
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS20) // Disable prescaler -> 62.5kHz
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS21) // 1/8 prescaler -> 7.8kHz (Used in v0.9)
|
||||
// #define SPINDLE_TCCRB_INIT_MASK ((1<<CS21) | (1<<CS20)) // 1/32 prescaler -> 1.96kHz
|
||||
#define SPINDLE_TCCRB_INIT_MASK (1 << CS22) // 1/64 prescaler -> 0.98kHz (J-tech laser)
|
||||
|
||||
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
|
||||
#define SPINDLE_PWM_DDR DDRB
|
||||
#define SPINDLE_PWM_PORT PORTB
|
||||
#define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
|
||||
|
||||
#else
|
||||
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
|
||||
#define SPINDLE_PWM_DDR DDRB
|
||||
#define SPINDLE_PWM_PORT PORTB
|
||||
#define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
|
||||
|
||||
// Dual axis feature requires an independent step pulse pin to operate. The independent direction pin is not
|
||||
// absolutely necessary but facilitates easy direction inverting with a Grbl $$ setting. These pins replace
|
||||
// the spindle direction and optional coolant mist pins.
|
||||
#else
|
||||
|
||||
#ifdef DUAL_AXIS_CONFIG_PROTONEER_V3_51
|
||||
// NOTE: Step pulse and direction pins may be on any port and output pin.
|
||||
#define STEP_DDR_DUAL DDRC
|
||||
#define STEP_PORT_DUAL PORTC
|
||||
#define DUAL_STEP_BIT 4 // Uno Analog Pin 4
|
||||
#define STEP_MASK_DUAL ((1<<DUAL_STEP_BIT))
|
||||
#define DIRECTION_DDR_DUAL DDRC
|
||||
#define DIRECTION_PORT_DUAL PORTC
|
||||
#define DUAL_DIRECTION_BIT 3 // Uno Analog Pin 3
|
||||
#define DIRECTION_MASK_DUAL ((1<<DUAL_DIRECTION_BIT))
|
||||
// Dual axis feature requires an independent step pulse pin to operate. The independent direction pin is not
|
||||
// absolutely necessary but facilitates easy direction inverting with a Grbl $$ setting. These pins replace
|
||||
// the spindle direction and optional coolant mist pins.
|
||||
|
||||
// NOTE: Dual axis limit is shared with the z-axis limit pin by default. Pin used must be on the same port
|
||||
// as other limit pins.
|
||||
#define DUAL_LIMIT_BIT Z_LIMIT_BIT
|
||||
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)|(1<<DUAL_LIMIT_BIT))
|
||||
#ifdef DUAL_AXIS_CONFIG_PROTONEER_V3_51
|
||||
// NOTE: Step pulse and direction pins may be on any port and output pin.
|
||||
#define STEP_DDR_DUAL DDRC
|
||||
#define STEP_PORT_DUAL PORTC
|
||||
#define DUAL_STEP_BIT 4 // Uno Analog Pin 4
|
||||
#define STEP_MASK_DUAL ((1 << DUAL_STEP_BIT))
|
||||
#define DIRECTION_DDR_DUAL DDRC
|
||||
#define DIRECTION_PORT_DUAL PORTC
|
||||
#define DUAL_DIRECTION_BIT 3 // Uno Analog Pin 3
|
||||
#define DIRECTION_MASK_DUAL ((1 << DUAL_DIRECTION_BIT))
|
||||
|
||||
// Define coolant enable output pins.
|
||||
// NOTE: Coolant flood moved from A3 to A4. Coolant mist not supported with dual axis feature on Arduino Uno.
|
||||
#define COOLANT_FLOOD_DDR DDRB
|
||||
#define COOLANT_FLOOD_PORT PORTB
|
||||
#define COOLANT_FLOOD_BIT 5 // Uno Digital Pin 13
|
||||
// NOTE: Dual axis limit is shared with the z-axis limit pin by default. Pin used must be on the same port
|
||||
// as other limit pins.
|
||||
#define DUAL_LIMIT_BIT Z_LIMIT_BIT
|
||||
#define LIMIT_MASK ((1 << X_LIMIT_BIT) | (1 << Y_LIMIT_BIT) | (1 << Z_LIMIT_BIT) | (1 << DUAL_LIMIT_BIT))
|
||||
|
||||
// Define spindle enable output pin.
|
||||
// NOTE: Spindle enable moved from D12 to A3 (old coolant flood enable pin). Spindle direction pin is removed.
|
||||
#define SPINDLE_ENABLE_DDR DDRB
|
||||
#define SPINDLE_ENABLE_PORT PORTB
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// NOTE: USE_SPINDLE_DIR_AS_ENABLE_PIN not supported with dual axis feature.
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
|
||||
#endif
|
||||
// Define coolant enable output pins.
|
||||
// NOTE: Coolant flood moved from A3 to A4. Coolant mist not supported with dual axis feature on Arduino Uno.
|
||||
#define COOLANT_FLOOD_DDR DDRB
|
||||
#define COOLANT_FLOOD_PORT PORTB
|
||||
#define COOLANT_FLOOD_BIT 5 // Uno Digital Pin 13
|
||||
|
||||
// Variable spindle configuration below. Do not change unless you know what you are doing.
|
||||
// NOTE: Only used when variable spindle is enabled.
|
||||
#define SPINDLE_PWM_MAX_VALUE 255 // Don't change. 328p fast PWM mode fixes top value as 255.
|
||||
#ifndef SPINDLE_PWM_MIN_VALUE
|
||||
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
|
||||
#endif
|
||||
#define SPINDLE_PWM_OFF_VALUE 0
|
||||
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)
|
||||
#define SPINDLE_TCCRA_REGISTER TCCR2A
|
||||
#define SPINDLE_TCCRB_REGISTER TCCR2B
|
||||
#define SPINDLE_OCR_REGISTER OCR2A
|
||||
#define SPINDLE_COMB_BIT COM2A1
|
||||
// Define spindle enable output pin.
|
||||
// NOTE: Spindle enable moved from D12 to A3 (old coolant flood enable pin). Spindle direction pin is removed.
|
||||
#define SPINDLE_ENABLE_DDR DDRB
|
||||
#define SPINDLE_ENABLE_PORT PORTB
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// NOTE: USE_SPINDLE_DIR_AS_ENABLE_PIN not supported with dual axis feature.
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Digital Pin 11
|
||||
#else
|
||||
#define SPINDLE_ENABLE_BIT 4 // Uno Digital Pin 12
|
||||
#endif
|
||||
|
||||
// Prescaled, 8-bit Fast PWM mode.
|
||||
#define SPINDLE_TCCRA_INIT_MASK ((1<<WGM20) | (1<<WGM21)) // Configures fast PWM mode.
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS20) // Disable prescaler -> 62.5kHz
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS21) // 1/8 prescaler -> 7.8kHz (Used in v0.9)
|
||||
// #define SPINDLE_TCCRB_INIT_MASK ((1<<CS21) | (1<<CS20)) // 1/32 prescaler -> 1.96kHz
|
||||
#define SPINDLE_TCCRB_INIT_MASK (1<<CS22) // 1/64 prescaler -> 0.98kHz (J-tech laser)
|
||||
// Variable spindle configuration below. Do not change unless you know what you are doing.
|
||||
// NOTE: Only used when variable spindle is enabled.
|
||||
#define SPINDLE_PWM_MAX_VALUE 255 // Don't change. 328p fast PWM mode fixes top value as 255.
|
||||
#ifndef SPINDLE_PWM_MIN_VALUE
|
||||
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
|
||||
#endif
|
||||
#define SPINDLE_PWM_OFF_VALUE 0
|
||||
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE - SPINDLE_PWM_MIN_VALUE)
|
||||
#define SPINDLE_TCCRA_REGISTER TCCR2A
|
||||
#define SPINDLE_TCCRB_REGISTER TCCR2B
|
||||
#define SPINDLE_OCR_REGISTER OCR2A
|
||||
#define SPINDLE_COMB_BIT COM2A1
|
||||
|
||||
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
|
||||
#define SPINDLE_PWM_DDR DDRB
|
||||
#define SPINDLE_PWM_PORT PORTB
|
||||
#define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
// Prescaled, 8-bit Fast PWM mode.
|
||||
#define SPINDLE_TCCRA_INIT_MASK ((1 << WGM20) | (1 << WGM21)) // Configures fast PWM mode.
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS20) // Disable prescaler -> 62.5kHz
|
||||
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS21) // 1/8 prescaler -> 7.8kHz (Used in v0.9)
|
||||
// #define SPINDLE_TCCRB_INIT_MASK ((1<<CS21) | (1<<CS20)) // 1/32 prescaler -> 1.96kHz
|
||||
#define SPINDLE_TCCRB_INIT_MASK (1 << CS22) // 1/64 prescaler -> 0.98kHz (J-tech laser)
|
||||
|
||||
// NOTE: Variable spindle not supported with this shield.
|
||||
#ifdef DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE
|
||||
// NOTE: Step pulse and direction pins may be on any port and output pin.
|
||||
#define STEP_DDR_DUAL DDRB
|
||||
#define STEP_PORT_DUAL PORTB
|
||||
#define DUAL_STEP_BIT 4 // Uno Digital Pin 12
|
||||
#define STEP_MASK_DUAL ((1<<DUAL_STEP_BIT))
|
||||
#define DIRECTION_DDR_DUAL DDRB
|
||||
#define DIRECTION_PORT_DUAL PORTB
|
||||
#define DUAL_DIRECTION_BIT 5 // Uno Digital Pin 13
|
||||
#define DIRECTION_MASK_DUAL ((1<<DUAL_DIRECTION_BIT))
|
||||
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
|
||||
#define SPINDLE_PWM_DDR DDRB
|
||||
#define SPINDLE_PWM_PORT PORTB
|
||||
#define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
|
||||
#endif
|
||||
|
||||
// NOTE: Dual axis limit is shared with the z-axis limit pin by default.
|
||||
#define DUAL_LIMIT_BIT Z_LIMIT_BIT
|
||||
#define LIMIT_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)|(1<<Z_LIMIT_BIT)|(1<<DUAL_LIMIT_BIT))
|
||||
// NOTE: Variable spindle not supported with this shield.
|
||||
#ifdef DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE
|
||||
// NOTE: Step pulse and direction pins may be on any port and output pin.
|
||||
#define STEP_DDR_DUAL DDRB
|
||||
#define STEP_PORT_DUAL PORTB
|
||||
#define DUAL_STEP_BIT 4 // Uno Digital Pin 12
|
||||
#define STEP_MASK_DUAL ((1 << DUAL_STEP_BIT))
|
||||
#define DIRECTION_DDR_DUAL DDRB
|
||||
#define DIRECTION_PORT_DUAL PORTB
|
||||
#define DUAL_DIRECTION_BIT 5 // Uno Digital Pin 13
|
||||
#define DIRECTION_MASK_DUAL ((1 << DUAL_DIRECTION_BIT))
|
||||
|
||||
// Define coolant enable output pins.
|
||||
// NOTE: Coolant flood moved from A3 to A4. Coolant mist not supported with dual axis feature on Arduino Uno.
|
||||
#define COOLANT_FLOOD_DDR DDRC
|
||||
#define COOLANT_FLOOD_PORT PORTC
|
||||
#define COOLANT_FLOOD_BIT 4 // Uno Analog Pin 4
|
||||
// NOTE: Dual axis limit is shared with the z-axis limit pin by default.
|
||||
#define DUAL_LIMIT_BIT Z_LIMIT_BIT
|
||||
#define LIMIT_MASK ((1 << X_LIMIT_BIT) | (1 << Y_LIMIT_BIT) | (1 << Z_LIMIT_BIT) | (1 << DUAL_LIMIT_BIT))
|
||||
|
||||
// Define spindle enable output pin.
|
||||
// NOTE: Spindle enable moved from D12 to A3 (old coolant flood enable pin). Spindle direction pin is removed.
|
||||
#define SPINDLE_ENABLE_DDR DDRC
|
||||
#define SPINDLE_ENABLE_PORT PORTC
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Analog Pin 3
|
||||
#endif
|
||||
// Define coolant enable output pins.
|
||||
// NOTE: Coolant flood moved from A3 to A4. Coolant mist not supported with dual axis feature on Arduino Uno.
|
||||
#define COOLANT_FLOOD_DDR DDRC
|
||||
#define COOLANT_FLOOD_PORT PORTC
|
||||
#define COOLANT_FLOOD_BIT 4 // Uno Analog Pin 4
|
||||
|
||||
#endif
|
||||
// Define spindle enable output pin.
|
||||
// NOTE: Spindle enable moved from D12 to A3 (old coolant flood enable pin). Spindle direction pin is removed.
|
||||
#define SPINDLE_ENABLE_DDR DDRC
|
||||
#define SPINDLE_ENABLE_PORT PORTC
|
||||
#define SPINDLE_ENABLE_BIT 3 // Uno Analog Pin 3
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
1004
grbl/defaults.h
1004
grbl/defaults.h
File diff suppressed because it is too large
Load diff
192
grbl/eeprom.c
192
grbl/eeprom.c
|
|
@ -1,33 +1,33 @@
|
|||
// This file has been prepared for Doxygen automatic documentation generation.
|
||||
/*! \file ********************************************************************
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* \li File: eeprom.c
|
||||
* \li Compiler: IAR EWAAVR 3.10c
|
||||
* \li Support mail: avr@atmel.com
|
||||
*
|
||||
* \li Supported devices: All devices with split EEPROM erase/write
|
||||
* capabilities can be used.
|
||||
* The example is written for ATmega48.
|
||||
*
|
||||
* \li AppNote: AVR103 - Using the EEPROM Programming Modes.
|
||||
*
|
||||
* \li Description: Example on how to use the split EEPROM erase/write
|
||||
* capabilities in e.g. ATmega48. All EEPROM
|
||||
* programming modes are tested, i.e. Erase+Write,
|
||||
* Erase-only and Write-only.
|
||||
*
|
||||
* $Revision: 1.6 $
|
||||
* $Date: Friday, February 11, 2005 07:16:44 UTC $
|
||||
****************************************************************************/
|
||||
#include <avr/io.h>
|
||||
*
|
||||
* Atmel Corporation
|
||||
*
|
||||
* \li File: eeprom.c
|
||||
* \li Compiler: IAR EWAAVR 3.10c
|
||||
* \li Support mail: avr@atmel.com
|
||||
*
|
||||
* \li Supported devices: All devices with split EEPROM erase/write
|
||||
* capabilities can be used.
|
||||
* The example is written for ATmega48.
|
||||
*
|
||||
* \li AppNote: AVR103 - Using the EEPROM Programming Modes.
|
||||
*
|
||||
* \li Description: Example on how to use the split EEPROM erase/write
|
||||
* capabilities in e.g. ATmega48. All EEPROM
|
||||
* programming modes are tested, i.e. Erase+Write,
|
||||
* Erase-only and Write-only.
|
||||
*
|
||||
* $Revision: 1.6 $
|
||||
* $Date: Friday, February 11, 2005 07:16:44 UTC $
|
||||
****************************************************************************/
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
|
||||
/* These EEPROM bits have different names on different devices. */
|
||||
#ifndef EEPE
|
||||
#define EEPE EEWE //!< EEPROM program/write enable.
|
||||
#define EEMPE EEMWE //!< EEPROM master program/write enable.
|
||||
#define EEPE EEWE //!< EEPROM program/write enable.
|
||||
#define EEMPE EEMWE //!< EEPROM master program/write enable.
|
||||
#endif
|
||||
|
||||
/* These two are unfortunately not defined in the device include files. */
|
||||
|
|
@ -46,12 +46,12 @@
|
|||
* \param addr EEPROM address to read from.
|
||||
* \return The byte read from the EEPROM address.
|
||||
*/
|
||||
unsigned char eeprom_get_char( unsigned int addr )
|
||||
{
|
||||
do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
|
||||
EEAR = addr; // Set EEPROM address register.
|
||||
EECR = (1<<EERE); // Start EEPROM read operation.
|
||||
return EEDR; // Return the byte read from EEPROM.
|
||||
unsigned char eeprom_get_char(unsigned int addr) {
|
||||
do {
|
||||
} while (EECR & (1 << EEPE)); // Wait for completion of previous write.
|
||||
EEAR = addr; // Set EEPROM address register.
|
||||
EECR = (1 << EERE); // Start EEPROM read operation.
|
||||
return EEDR; // Return the byte read from EEPROM.
|
||||
}
|
||||
|
||||
/*! \brief Write byte to EEPROM.
|
||||
|
|
@ -71,81 +71,81 @@ unsigned char eeprom_get_char( unsigned int addr )
|
|||
* \param addr EEPROM address to write to.
|
||||
* \param new_value New EEPROM value.
|
||||
*/
|
||||
void eeprom_put_char( unsigned int addr, unsigned char new_value )
|
||||
{
|
||||
char old_value; // Old EEPROM value.
|
||||
char diff_mask; // Difference mask, i.e. old value XOR new value.
|
||||
void eeprom_put_char(unsigned int addr, unsigned char new_value) {
|
||||
char old_value; // Old EEPROM value.
|
||||
char diff_mask; // Difference mask, i.e. old value XOR new value.
|
||||
|
||||
cli(); // Ensure atomic operation for the write operation.
|
||||
|
||||
do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
|
||||
#ifndef EEPROM_IGNORE_SELFPROG
|
||||
do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM.
|
||||
#endif
|
||||
|
||||
EEAR = addr; // Set EEPROM address register.
|
||||
EECR = (1<<EERE); // Start EEPROM read operation.
|
||||
old_value = EEDR; // Get old EEPROM value.
|
||||
diff_mask = old_value ^ new_value; // Get bit differences.
|
||||
|
||||
// Check if any bits are changed to '1' in the new value.
|
||||
if( diff_mask & new_value ) {
|
||||
// Now we know that _some_ bits need to be erased to '1'.
|
||||
|
||||
// Check if any bits in the new value are '0'.
|
||||
if( new_value != 0xff ) {
|
||||
// Now we know that some bits need to be programmed to '0' also.
|
||||
|
||||
EEDR = new_value; // Set EEPROM data register.
|
||||
EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
||||
(0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode.
|
||||
EECR |= (1<<EEPE); // Start Erase+Write operation.
|
||||
} else {
|
||||
// Now we know that all bits should be erased.
|
||||
cli(); // Ensure atomic operation for the write operation.
|
||||
|
||||
EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
||||
(1<<EEPM0); // ...and Erase-only mode.
|
||||
EECR |= (1<<EEPE); // Start Erase-only operation.
|
||||
}
|
||||
} else {
|
||||
// Now we know that _no_ bits need to be erased to '1'.
|
||||
|
||||
// Check if any bits are changed from '1' in the old value.
|
||||
if( diff_mask ) {
|
||||
// Now we know that _some_ bits need to the programmed to '0'.
|
||||
|
||||
EEDR = new_value; // Set EEPROM data register.
|
||||
EECR = (1<<EEMPE) | // Set Master Write Enable bit...
|
||||
(1<<EEPM1); // ...and Write-only mode.
|
||||
EECR |= (1<<EEPE); // Start Write-only operation.
|
||||
}
|
||||
}
|
||||
|
||||
sei(); // Restore interrupt flag state.
|
||||
do {
|
||||
} while (EECR & (1 << EEPE)); // Wait for completion of previous write.
|
||||
#ifndef EEPROM_IGNORE_SELFPROG
|
||||
do {
|
||||
} while (SPMCSR & (1 << SELFPRGEN)); // Wait for completion of SPM.
|
||||
#endif
|
||||
|
||||
EEAR = addr; // Set EEPROM address register.
|
||||
EECR = (1 << EERE); // Start EEPROM read operation.
|
||||
old_value = EEDR; // Get old EEPROM value.
|
||||
diff_mask = old_value ^ new_value; // Get bit differences.
|
||||
|
||||
// Check if any bits are changed to '1' in the new value.
|
||||
if (diff_mask & new_value) {
|
||||
// Now we know that _some_ bits need to be erased to '1'.
|
||||
|
||||
// Check if any bits in the new value are '0'.
|
||||
if (new_value != 0xff) {
|
||||
// Now we know that some bits need to be programmed to '0' also.
|
||||
|
||||
EEDR = new_value; // Set EEPROM data register.
|
||||
EECR = (1 << EEMPE) | // Set Master Write Enable bit...
|
||||
(0 << EEPM1) | (0 << EEPM0); // ...and Erase+Write mode.
|
||||
EECR |= (1 << EEPE); // Start Erase+Write operation.
|
||||
} else {
|
||||
// Now we know that all bits should be erased.
|
||||
|
||||
EECR = (1 << EEMPE) | // Set Master Write Enable bit...
|
||||
(1 << EEPM0); // ...and Erase-only mode.
|
||||
EECR |= (1 << EEPE); // Start Erase-only operation.
|
||||
}
|
||||
} else {
|
||||
// Now we know that _no_ bits need to be erased to '1'.
|
||||
|
||||
// Check if any bits are changed from '1' in the old value.
|
||||
if (diff_mask) {
|
||||
// Now we know that _some_ bits need to the programmed to '0'.
|
||||
|
||||
EEDR = new_value; // Set EEPROM data register.
|
||||
EECR = (1 << EEMPE) | // Set Master Write Enable bit...
|
||||
(1 << EEPM1); // ...and Write-only mode.
|
||||
EECR |= (1 << EEPE); // Start Write-only operation.
|
||||
}
|
||||
}
|
||||
|
||||
sei(); // Restore interrupt flag state.
|
||||
}
|
||||
|
||||
// Extensions added as part of Grbl
|
||||
|
||||
// Extensions added as part of Grbl
|
||||
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size) {
|
||||
unsigned char checksum = 0;
|
||||
for(; size > 0; size--) {
|
||||
checksum = ((checksum << 1) != 0) || (checksum >> 7);
|
||||
checksum += *source;
|
||||
eeprom_put_char(destination++, *(source++));
|
||||
}
|
||||
eeprom_put_char(destination, checksum);
|
||||
unsigned char checksum = 0;
|
||||
for (; size > 0; size--) {
|
||||
checksum = ((checksum << 1) != 0) || (checksum >> 7);
|
||||
checksum += *source;
|
||||
eeprom_put_char(destination++, *(source++));
|
||||
}
|
||||
eeprom_put_char(destination, checksum);
|
||||
}
|
||||
|
||||
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) {
|
||||
unsigned char data, checksum = 0;
|
||||
for(; size > 0; size--) {
|
||||
data = eeprom_get_char(source++);
|
||||
checksum = ((checksum << 1) != 0) || (checksum >> 7);
|
||||
checksum += data;
|
||||
*(destination++) = data;
|
||||
}
|
||||
return(checksum == eeprom_get_char(source));
|
||||
unsigned char data, checksum = 0;
|
||||
for (; size > 0; size--) {
|
||||
data = eeprom_get_char(source++);
|
||||
checksum = ((checksum << 1) != 0) || (checksum >> 7);
|
||||
checksum += data;
|
||||
*(destination++) = data;
|
||||
}
|
||||
return (checksum == eeprom_get_char(source));
|
||||
}
|
||||
|
||||
// end of file
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
#define eeprom_h
|
||||
|
||||
unsigned char eeprom_get_char(unsigned int addr);
|
||||
void eeprom_put_char(unsigned int addr, unsigned char new_value);
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size);
|
||||
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size);
|
||||
void eeprom_put_char(unsigned int addr, unsigned char new_value);
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size);
|
||||
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
2257
grbl/gcode.c
2257
grbl/gcode.c
File diff suppressed because it is too large
Load diff
244
grbl/gcode.h
244
grbl/gcode.h
|
|
@ -22,59 +22,58 @@
|
|||
#ifndef gcode_h
|
||||
#define gcode_h
|
||||
|
||||
|
||||
// Define modal group internal numbers for checking multiple command violations and tracking the
|
||||
// type of command that is called in the block. A modal group is a group of g-code commands that are
|
||||
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
|
||||
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
|
||||
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
|
||||
// NOTE: Modal group define values must be sequential and starting from zero.
|
||||
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
|
||||
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
|
||||
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
|
||||
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
|
||||
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
|
||||
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
|
||||
#define MODAL_GROUP_G6 6 // [G20,G21] Units
|
||||
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
|
||||
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
|
||||
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
|
||||
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
|
||||
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
|
||||
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
|
||||
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
|
||||
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
|
||||
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
|
||||
#define MODAL_GROUP_G6 6 // [G20,G21] Units
|
||||
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
|
||||
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
|
||||
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
|
||||
#define MODAL_GROUP_G13 10 // [G61] Control mode
|
||||
|
||||
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
|
||||
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
|
||||
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
|
||||
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
|
||||
#define MODAL_GROUP_M9 14 // [M56] Override control
|
||||
|
||||
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
|
||||
// internally by the parser to know which command to execute.
|
||||
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
|
||||
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
|
||||
// compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not
|
||||
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
|
||||
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
|
||||
// to see how they are used, if you need to alter them.
|
||||
|
||||
// Modal Group G0: Non-modal actions
|
||||
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
|
||||
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
|
||||
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
|
||||
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value)
|
||||
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
|
||||
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
|
||||
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
|
||||
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 // G92.1 (Do not alter value)
|
||||
|
||||
// Modal Group G1: Motion modes
|
||||
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
|
||||
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
|
||||
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
|
||||
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
|
||||
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
|
||||
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
|
||||
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
|
||||
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
|
||||
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
|
||||
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
|
||||
|
||||
// Modal Group G2: Plane select
|
||||
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
|
||||
|
|
@ -82,25 +81,25 @@
|
|||
#define PLANE_SELECT_YZ 2 // G19 (Do not alter value)
|
||||
|
||||
// Modal Group G3: Distance mode
|
||||
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
|
||||
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
|
||||
#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value)
|
||||
|
||||
// Modal Group G4: Arc IJK distance mode
|
||||
#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
|
||||
|
||||
// Modal Group M4: Program flow
|
||||
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
|
||||
#define PROGRAM_FLOW_PAUSED 3 // M0
|
||||
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
|
||||
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
|
||||
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
|
||||
#define PROGRAM_FLOW_PAUSED 3 // M0
|
||||
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
|
||||
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
|
||||
#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value)
|
||||
|
||||
// Modal Group G5: Feed rate mode
|
||||
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
|
||||
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
|
||||
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
|
||||
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
|
||||
|
||||
// Modal Group G6: Units mode
|
||||
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
|
||||
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
|
||||
#define UNITS_MODE_INCHES 1 // G20 (Do not alter value)
|
||||
|
||||
// Modal Group G7: Cutter radius compensation mode
|
||||
|
|
@ -110,132 +109,129 @@
|
|||
#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero)
|
||||
|
||||
// Modal Group M7: Spindle control
|
||||
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
|
||||
#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
|
||||
#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M8: Coolant control
|
||||
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
|
||||
#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
|
||||
#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group G8: Tool length offset
|
||||
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
|
||||
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
|
||||
#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1
|
||||
|
||||
// Modal Group M9: Override control
|
||||
#ifdef DEACTIVATE_PARKING_UPON_INIT
|
||||
#define OVERRIDE_DISABLED 0 // (Default: Must be zero)
|
||||
#define OVERRIDE_PARKING_MOTION 1 // M56
|
||||
#define OVERRIDE_DISABLED 0 // (Default: Must be zero)
|
||||
#define OVERRIDE_PARKING_MOTION 1 // M56
|
||||
#else
|
||||
#define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero)
|
||||
#define OVERRIDE_DISABLED 1 // Parking disabled.
|
||||
#define OVERRIDE_PARKING_MOTION 0 // M56 (Default: Must be zero)
|
||||
#define OVERRIDE_DISABLED 1 // Parking disabled.
|
||||
#endif
|
||||
|
||||
// Modal Group G12: Active work coordinate system
|
||||
// N/A: Stores coordinate system value (54-59) to change to.
|
||||
|
||||
// Define parameter word mapping.
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
#define WORD_J 2
|
||||
#define WORD_K 3
|
||||
#define WORD_L 4
|
||||
#define WORD_N 5
|
||||
#define WORD_P 6
|
||||
#define WORD_R 7
|
||||
#define WORD_S 8
|
||||
#define WORD_T 9
|
||||
#define WORD_X 10
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
#define WORD_J 2
|
||||
#define WORD_K 3
|
||||
#define WORD_L 4
|
||||
#define WORD_N 5
|
||||
#define WORD_P 6
|
||||
#define WORD_R 7
|
||||
#define WORD_S 8
|
||||
#define WORD_T 9
|
||||
#define WORD_X 10
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
|
||||
// Define g-code parser position updating flags
|
||||
#define GC_UPDATE_POS_TARGET 0 // Must be zero
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
#define GC_UPDATE_POS_TARGET 0 // Must be zero
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
|
||||
// Define probe cycle exit states and assign proper position updating.
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#ifdef SET_CHECK_MODE_PROBE_TO_START
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#else
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#endif
|
||||
|
||||
// Define gcode parser flags for handling special cases.
|
||||
#define GC_PARSER_NONE 0 // Must be zero.
|
||||
#define GC_PARSER_JOG_MOTION bit(0)
|
||||
#define GC_PARSER_CHECK_MANTISSA bit(1)
|
||||
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
|
||||
#define GC_PARSER_PROBE_IS_AWAY bit(3)
|
||||
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
|
||||
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
|
||||
#define GC_PARSER_LASER_DISABLE bit(6)
|
||||
#define GC_PARSER_LASER_ISMOTION bit(7)
|
||||
|
||||
#define GC_PARSER_NONE 0 // Must be zero.
|
||||
#define GC_PARSER_JOG_MOTION bit(0)
|
||||
#define GC_PARSER_CHECK_MANTISSA bit(1)
|
||||
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
|
||||
#define GC_PARSER_PROBE_IS_AWAY bit(3)
|
||||
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
|
||||
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
|
||||
#define GC_PARSER_LASER_DISABLE bit(6)
|
||||
#define GC_PARSER_LASER_ISMOTION bit(7)
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
typedef struct {
|
||||
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
|
||||
uint8_t feed_rate; // {G93,G94}
|
||||
uint8_t units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
|
||||
uint8_t plane_select; // {G17,G18,G19}
|
||||
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
|
||||
uint8_t tool_length; // {G43.1,G49}
|
||||
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
|
||||
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
|
||||
uint8_t program_flow; // {M0,M1,M2,M30}
|
||||
uint8_t coolant; // {M7,M8,M9}
|
||||
uint8_t spindle; // {M3,M4,M5}
|
||||
uint8_t override; // {M56}
|
||||
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
|
||||
uint8_t feed_rate; // {G93,G94}
|
||||
uint8_t units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
|
||||
uint8_t plane_select; // {G17,G18,G19}
|
||||
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
|
||||
uint8_t tool_length; // {G43.1,G49}
|
||||
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
|
||||
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
|
||||
uint8_t program_flow; // {M0,M1,M2,M30}
|
||||
uint8_t coolant; // {M7,M8,M9}
|
||||
uint8_t spindle; // {M3,M4,M5}
|
||||
uint8_t override; // {M56}
|
||||
} gc_modal_t;
|
||||
|
||||
typedef struct {
|
||||
float f; // Feed
|
||||
float ijk[3]; // I,J,K Axis arc offsets
|
||||
uint8_t l; // G10 or canned cycles parameters
|
||||
int32_t n; // Line number
|
||||
float p; // G10 or dwell parameters
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[3]; // X,Y,Z Translational axes
|
||||
float f; // Feed
|
||||
float ijk[3]; // I,J,K Axis arc offsets
|
||||
uint8_t l; // G10 or canned cycles parameters
|
||||
int32_t n; // Line number
|
||||
float p; // G10 or dwell parameters
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[3]; // X,Y,Z Translational axes
|
||||
} gc_values_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
gc_modal_t modal;
|
||||
gc_modal_t modal;
|
||||
|
||||
float spindle_speed; // RPM
|
||||
float feed_rate; // Millimeters/min
|
||||
uint8_t tool; // Tracks tool number. NOT USED.
|
||||
int32_t line_number; // Last line number sent
|
||||
float spindle_speed; // RPM
|
||||
float feed_rate; // Millimeters/min
|
||||
uint8_t tool; // Tracks tool number. NOT USED.
|
||||
int32_t line_number; // Last line number sent
|
||||
|
||||
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
|
||||
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
|
||||
|
||||
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
|
||||
// position in mm. Loaded from EEPROM when called.
|
||||
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
|
||||
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
|
||||
float tool_length_offset; // Tracks tool length offset value when enabled.
|
||||
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
|
||||
// position in mm. Loaded from EEPROM when called.
|
||||
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
|
||||
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
|
||||
float tool_length_offset; // Tracks tool length offset value when enabled.
|
||||
} parser_state_t;
|
||||
|
||||
extern parser_state_t gc_state;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t non_modal_command;
|
||||
gc_modal_t modal;
|
||||
gc_values_t values;
|
||||
uint8_t non_modal_command;
|
||||
gc_modal_t modal;
|
||||
gc_values_t values;
|
||||
} parser_block_t;
|
||||
|
||||
|
||||
// Initialize the parser
|
||||
void gc_init();
|
||||
|
||||
|
|
|
|||
103
grbl/grbl.h
103
grbl/grbl.h
|
|
@ -22,117 +22,116 @@
|
|||
#define grbl_h
|
||||
|
||||
// Grbl versioning system
|
||||
#define GRBL_VERSION "1.1h"
|
||||
#define GRBL_VERSION "1.1h"
|
||||
#define GRBL_VERSION_BUILD "20190830"
|
||||
|
||||
// Define standard libraries used by Grbl.
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/delay.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
// Define the Grbl system include files. NOTE: Do not alter organization.
|
||||
#include "config.h"
|
||||
#include "nuts_bolts.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include "defaults.h"
|
||||
#include "cpu_map.h"
|
||||
#include "planner.h"
|
||||
#include "coolant_control.h"
|
||||
#include "cpu_map.h"
|
||||
#include "defaults.h"
|
||||
#include "eeprom.h"
|
||||
#include "gcode.h"
|
||||
#include "jog.h"
|
||||
#include "limits.h"
|
||||
#include "motion_control.h"
|
||||
#include "nuts_bolts.h"
|
||||
#include "planner.h"
|
||||
#include "print.h"
|
||||
#include "probe.h"
|
||||
#include "protocol.h"
|
||||
#include "report.h"
|
||||
#include "serial.h"
|
||||
#include "settings.h"
|
||||
#include "spindle_control.h"
|
||||
#include "stepper.h"
|
||||
#include "jog.h"
|
||||
#include "system.h"
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// COMPILE-TIME ERROR CHECKING OF DEFINE VALUES:
|
||||
|
||||
#ifndef HOMING_CYCLE_0
|
||||
#error "Required HOMING_CYCLE_0 not defined."
|
||||
#error "Required HOMING_CYCLE_0 not defined."
|
||||
#endif
|
||||
|
||||
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(VARIABLE_SPINDLE)
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with VARIABLE_SPINDLE enabled"
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with VARIABLE_SPINDLE enabled"
|
||||
#endif
|
||||
|
||||
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(CPU_MAP_ATMEGA328P)
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with a 328p processor"
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN may only be used with a 328p processor"
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)
|
||||
#error "SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED may only be used with USE_SPINDLE_DIR_AS_ENABLE_PIN enabled"
|
||||
#error "SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED may only be used with USE_SPINDLE_DIR_AS_ENABLE_PIN enabled"
|
||||
#endif
|
||||
|
||||
#if defined(PARKING_ENABLE)
|
||||
#if defined(HOMING_FORCE_SET_ORIGIN)
|
||||
#error "HOMING_FORCE_SET_ORIGIN is not supported with PARKING_ENABLE at this time."
|
||||
#endif
|
||||
#if defined(HOMING_FORCE_SET_ORIGIN)
|
||||
#error "HOMING_FORCE_SET_ORIGIN is not supported with PARKING_ENABLE at this time."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_PARKING_OVERRIDE_CONTROL)
|
||||
#if !defined(PARKING_ENABLE)
|
||||
#error "ENABLE_PARKING_OVERRIDE_CONTROL must be enabled with PARKING_ENABLE."
|
||||
#endif
|
||||
#if !defined(PARKING_ENABLE)
|
||||
#error "ENABLE_PARKING_OVERRIDE_CONTROL must be enabled with PARKING_ENABLE."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SPINDLE_PWM_MIN_VALUE)
|
||||
#if !(SPINDLE_PWM_MIN_VALUE > 0)
|
||||
#error "SPINDLE_PWM_MIN_VALUE must be greater than zero."
|
||||
#endif
|
||||
#if !(SPINDLE_PWM_MIN_VALUE > 0)
|
||||
#error "SPINDLE_PWM_MIN_VALUE must be greater than zero."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (REPORT_WCO_REFRESH_BUSY_COUNT < REPORT_WCO_REFRESH_IDLE_COUNT)
|
||||
#error "WCO busy refresh is less than idle refresh."
|
||||
#error "WCO busy refresh is less than idle refresh."
|
||||
#endif
|
||||
#if (REPORT_OVR_REFRESH_BUSY_COUNT < REPORT_OVR_REFRESH_IDLE_COUNT)
|
||||
#error "Override busy refresh is less than idle refresh."
|
||||
#error "Override busy refresh is less than idle refresh."
|
||||
#endif
|
||||
#if (REPORT_WCO_REFRESH_IDLE_COUNT < 2)
|
||||
#error "WCO refresh must be greater than one."
|
||||
#error "WCO refresh must be greater than one."
|
||||
#endif
|
||||
#if (REPORT_OVR_REFRESH_IDLE_COUNT < 1)
|
||||
#error "Override refresh must be greater than zero."
|
||||
#error "Override refresh must be greater than zero."
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_DUAL_AXIS)
|
||||
#if !((DUAL_AXIS_SELECT == X_AXIS) || (DUAL_AXIS_SELECT == Y_AXIS))
|
||||
#error "Dual axis currently supports X or Y axes only."
|
||||
#endif
|
||||
#if defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && defined(VARIABLE_SPINDLE)
|
||||
#error "VARIABLE_SPINDLE not supported with DUAL_AXIS_CNC_SHIELD_CLONE."
|
||||
#endif
|
||||
#if defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && defined(DUAL_AXIS_CONFIG_PROTONEER_V3_51)
|
||||
#error "More than one dual axis configuration found. Select one."
|
||||
#endif
|
||||
#if !defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && !defined(DUAL_AXIS_CONFIG_PROTONEER_V3_51)
|
||||
#error "No supported dual axis configuration found. Select one."
|
||||
#endif
|
||||
#if defined(COREXY)
|
||||
#error "CORE XY not supported with dual axis feature."
|
||||
#endif
|
||||
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN not supported with dual axis feature."
|
||||
#endif
|
||||
#if defined(ENABLE_M7)
|
||||
#error "ENABLE_M7 not supported with dual axis feature."
|
||||
#endif
|
||||
#if !((DUAL_AXIS_SELECT == X_AXIS) || (DUAL_AXIS_SELECT == Y_AXIS))
|
||||
#error "Dual axis currently supports X or Y axes only."
|
||||
#endif
|
||||
#if defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && defined(VARIABLE_SPINDLE)
|
||||
#error "VARIABLE_SPINDLE not supported with DUAL_AXIS_CNC_SHIELD_CLONE."
|
||||
#endif
|
||||
#if defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && defined(DUAL_AXIS_CONFIG_PROTONEER_V3_51)
|
||||
#error "More than one dual axis configuration found. Select one."
|
||||
#endif
|
||||
#if !defined(DUAL_AXIS_CONFIG_CNC_SHIELD_CLONE) && !defined(DUAL_AXIS_CONFIG_PROTONEER_V3_51)
|
||||
#error "No supported dual axis configuration found. Select one."
|
||||
#endif
|
||||
#if defined(COREXY)
|
||||
#error "CORE XY not supported with dual axis feature."
|
||||
#endif
|
||||
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
|
||||
#error "USE_SPINDLE_DIR_AS_ENABLE_PIN not supported with dual axis feature."
|
||||
#endif
|
||||
#if defined(ENABLE_M7)
|
||||
#error "ENABLE_M7 not supported with dual axis feature."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
|
|
|||
44
grbl/jog.c
44
grbl/jog.c
|
|
@ -20,31 +20,31 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block)
|
||||
{
|
||||
// Initialize planner data struct for jogging motions.
|
||||
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
|
||||
pl_data->feed_rate = gc_block->values.f;
|
||||
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block) {
|
||||
// Initialize planner data struct for jogging motions.
|
||||
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
|
||||
pl_data->feed_rate = gc_block->values.f;
|
||||
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
pl_data->line_number = gc_block->values.n;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
if (system_check_travel_limits(gc_block->values.xyz)) { return(STATUS_TRAVEL_EXCEEDED); }
|
||||
}
|
||||
|
||||
// Valid jog command. Plan, set state, and execute.
|
||||
mc_line(gc_block->values.xyz,pl_data);
|
||||
if (sys.state == STATE_IDLE) {
|
||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||
sys.state = STATE_JOG;
|
||||
st_prep_buffer();
|
||||
st_wake_up(); // NOTE: Manual start. No state machine required.
|
||||
if (bit_istrue(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
if (system_check_travel_limits(gc_block->values.xyz)) {
|
||||
return (STATUS_TRAVEL_EXCEEDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(STATUS_OK);
|
||||
// Valid jog command. Plan, set state, and execute.
|
||||
mc_line(gc_block->values.xyz, pl_data);
|
||||
if (sys.state == STATE_IDLE) {
|
||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||
sys.state = STATE_JOG;
|
||||
st_prep_buffer();
|
||||
st_wake_up(); // NOTE: Manual start. No state machine required.
|
||||
}
|
||||
}
|
||||
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
|
|
|||
678
grbl/limits.c
678
grbl/limits.c
|
|
@ -21,130 +21,134 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
|
||||
#ifndef HOMING_AXIS_SEARCH_SCALAR
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged.
|
||||
#endif
|
||||
#ifndef HOMING_AXIS_LOCATE_SCALAR
|
||||
#define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
|
||||
#define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
// Flags for dual axis async limit trigger check.
|
||||
#define DUAL_AXIS_CHECK_DISABLE 0 // Must be zero
|
||||
#define DUAL_AXIS_CHECK_ENABLE bit(0)
|
||||
#define DUAL_AXIS_CHECK_TRIGGER_1 bit(1)
|
||||
#define DUAL_AXIS_CHECK_TRIGGER_2 bit(2)
|
||||
// Flags for dual axis async limit trigger check.
|
||||
#define DUAL_AXIS_CHECK_DISABLE 0 // Must be zero
|
||||
#define DUAL_AXIS_CHECK_ENABLE bit(0)
|
||||
#define DUAL_AXIS_CHECK_TRIGGER_1 bit(1)
|
||||
#define DUAL_AXIS_CHECK_TRIGGER_2 bit(2)
|
||||
#endif
|
||||
|
||||
void limits_init()
|
||||
{
|
||||
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
|
||||
void limits_init() {
|
||||
LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins
|
||||
|
||||
#ifdef DISABLE_LIMIT_PIN_PULL_UP
|
||||
#ifdef DISABLE_LIMIT_PIN_PULL_UP
|
||||
LIMIT_PORT &= ~(LIMIT_MASK); // Normal low operation. Requires external pull-down.
|
||||
#else
|
||||
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
#else
|
||||
LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
|
||||
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
|
||||
PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
|
||||
} else {
|
||||
limits_disable();
|
||||
}
|
||||
if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
|
||||
LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt
|
||||
PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt
|
||||
} else {
|
||||
limits_disable();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE);
|
||||
WDTCSR = (1<<WDP0); // Set time-out at ~32msec.
|
||||
#endif
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
MCUSR &= ~(1 << WDRF);
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
WDTCSR = (1 << WDP0); // Set time-out at ~32msec.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Disables hard limits.
|
||||
void limits_disable()
|
||||
{
|
||||
LIMIT_PCMSK &= ~LIMIT_MASK; // Disable specific pins of the Pin Change Interrupt
|
||||
PCICR &= ~(1 << LIMIT_INT); // Disable Pin Change Interrupt
|
||||
void limits_disable() {
|
||||
LIMIT_PCMSK &= ~LIMIT_MASK; // Disable specific pins of the Pin Change Interrupt
|
||||
PCICR &= ~(1 << LIMIT_INT); // Disable Pin Change Interrupt
|
||||
}
|
||||
|
||||
|
||||
// Returns limit state as a bit-wise uint8 variable. Each bit indicates an axis limit, where
|
||||
// triggered is 1 and not triggered is 0. Invert mask is applied. Axes are defined by their
|
||||
// number in bit position, i.e. Z_AXIS is (1<<2) or bit 2, and Y_AXIS is (1<<1) or bit 1.
|
||||
uint8_t limits_get_state()
|
||||
{
|
||||
uint8_t limit_state = 0;
|
||||
uint8_t pin = (LIMIT_PIN & LIMIT_MASK);
|
||||
#ifdef INVERT_LIMIT_PIN_MASK
|
||||
uint8_t limits_get_state() {
|
||||
uint8_t limit_state = 0;
|
||||
uint8_t pin = (LIMIT_PIN & LIMIT_MASK);
|
||||
#ifdef INVERT_LIMIT_PIN_MASK
|
||||
pin ^= INVERT_LIMIT_PIN_MASK;
|
||||
#endif
|
||||
if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { pin ^= LIMIT_MASK; }
|
||||
if (pin) {
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (pin & get_limit_pin_mask(idx)) { limit_state |= (1 << idx); }
|
||||
#endif
|
||||
if (bit_isfalse(settings.flags, BITFLAG_INVERT_LIMIT_PINS)) {
|
||||
pin ^= LIMIT_MASK;
|
||||
}
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (pin & (1<<DUAL_LIMIT_BIT)) { limit_state |= (1 << N_AXIS); }
|
||||
#endif
|
||||
}
|
||||
return(limit_state);
|
||||
if (pin) {
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (pin & get_limit_pin_mask(idx)) {
|
||||
limit_state |= (1 << idx);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (pin & (1 << DUAL_LIMIT_BIT)) {
|
||||
limit_state |= (1 << N_AXIS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (limit_state);
|
||||
}
|
||||
|
||||
|
||||
// This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing
|
||||
// limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
|
||||
// If a switch is triggered at all, something bad has happened and treat it as such, regardless
|
||||
// if a limit switch is being disengaged. It's impossible to reliably tell the state of a
|
||||
// bouncing pin because the Arduino microcontroller does not retain any state information when
|
||||
// detecting a pin change. If we poll the pins in the ISR, you can miss the correct reading if the
|
||||
// detecting a pin change. If we poll the pins in the ISR, you can miss the correct reading if the
|
||||
// switch is bouncing.
|
||||
// NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during
|
||||
// homing cycles and will not respond correctly. Upon user request or need, there may be a
|
||||
// special pinout for an e-stop, but it is generally recommended to just directly connect
|
||||
// your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
|
||||
#ifndef ENABLE_SOFTWARE_DEBOUNCE
|
||||
ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
|
||||
{
|
||||
ISR(LIMIT_INT_vect) // DEFAULT: Limit pin change interrupt process.
|
||||
{
|
||||
// Ignore limit switches if already in an alarm state or in-process of executing an alarm.
|
||||
// When in the alarm state, Grbl should have been reset or will force a reset, so any pending
|
||||
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
|
||||
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
|
||||
// limit setting if their limits are constantly triggering after a reset and move their axes.
|
||||
if (sys.state != STATE_ALARM) {
|
||||
if (!(sys_rt_exec_alarm)) {
|
||||
#ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
if (!(sys_rt_exec_alarm)) {
|
||||
#ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
#else
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
#else
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // OPTIONAL: Software debounce limit pin routine.
|
||||
// Upon limit pin change, enable watchdog timer to create a short delay.
|
||||
ISR(LIMIT_INT_vect) { if (!(WDTCSR & (1<<WDIE))) { WDTCSR |= (1<<WDIE); } }
|
||||
ISR(WDT_vect) // Watchdog timer ISR
|
||||
{
|
||||
WDTCSR &= ~(1<<WDIE); // Disable watchdog timer.
|
||||
if (sys.state != STATE_ALARM) { // Ignore if already in alarm state.
|
||||
if (!(sys_rt_exec_alarm)) {
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else // OPTIONAL: Software debounce limit pin routine.
|
||||
// Upon limit pin change, enable watchdog timer to create a short delay.
|
||||
ISR(LIMIT_INT_vect) {
|
||||
if (!(WDTCSR & (1 << WDIE))) {
|
||||
WDTCSR |= (1 << WDIE);
|
||||
}
|
||||
}
|
||||
|
||||
ISR(WDT_vect) // Watchdog timer ISR
|
||||
{
|
||||
WDTCSR &= ~(1 << WDIE); // Disable watchdog timer.
|
||||
if (sys.state != STATE_ALARM) { // Ignore if already in alarm state.
|
||||
if (!(sys_rt_exec_alarm)) {
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Homes the specified cycle axes, sets the machine position, and performs a pull-off motion after
|
||||
|
|
@ -154,277 +158,303 @@ uint8_t limits_get_state()
|
|||
// circumvent the processes for executing motions in normal operation.
|
||||
// NOTE: Only the abort realtime command can interrupt this process.
|
||||
// TODO: Move limit pin-specific calls to a general function for portability.
|
||||
void limits_go_home(uint8_t cycle_mask)
|
||||
{
|
||||
if (sys.abort) { return; } // Block if system reset has been issued.
|
||||
void limits_go_home(uint8_t cycle_mask) {
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Block if system reset has been issued.
|
||||
|
||||
// Initialize plan data struct for homing motion. Spindle and coolant are disabled.
|
||||
plan_line_data_t plan_data;
|
||||
plan_line_data_t *pl_data = &plan_data;
|
||||
memset(pl_data,0,sizeof(plan_line_data_t));
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
// Initialize plan data struct for homing motion. Spindle and coolant are disabled.
|
||||
plan_line_data_t plan_data;
|
||||
plan_line_data_t *pl_data = &plan_data;
|
||||
memset(pl_data, 0, sizeof(plan_line_data_t));
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
pl_data->line_number = HOMING_CYCLE_LINE_NUMBER;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize variables used for homing computations.
|
||||
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
|
||||
uint8_t step_pin[N_AXIS];
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
// Initialize variables used for homing computations.
|
||||
uint8_t n_cycle = (2 * N_HOMING_LOCATE_CYCLE + 1);
|
||||
uint8_t step_pin[N_AXIS];
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
uint8_t step_pin_dual;
|
||||
uint8_t dual_axis_async_check;
|
||||
int32_t dual_trigger_position;
|
||||
#if (DUAL_AXIS_SELECT == X_AXIS)
|
||||
float fail_distance = (-DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT/100.0)*settings.max_travel[Y_AXIS];
|
||||
#else
|
||||
float fail_distance = (-DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT/100.0)*settings.max_travel[X_AXIS];
|
||||
#endif
|
||||
#if (DUAL_AXIS_SELECT == X_AXIS)
|
||||
float fail_distance = (-DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT / 100.0) * settings.max_travel[Y_AXIS];
|
||||
#else
|
||||
float fail_distance = (-DUAL_AXIS_HOMING_FAIL_AXIS_LENGTH_PERCENT / 100.0) * settings.max_travel[X_AXIS];
|
||||
#endif
|
||||
fail_distance = min(fail_distance, DUAL_AXIS_HOMING_FAIL_DISTANCE_MAX);
|
||||
fail_distance = max(fail_distance, DUAL_AXIS_HOMING_FAIL_DISTANCE_MIN);
|
||||
int32_t dual_fail_distance = trunc(fail_distance*settings.steps_per_mm[DUAL_AXIS_SELECT]);
|
||||
// int32_t dual_fail_distance = trunc((DUAL_AXIS_HOMING_TRIGGER_FAIL_DISTANCE)*settings.steps_per_mm[DUAL_AXIS_SELECT]);
|
||||
#endif
|
||||
float target[N_AXIS];
|
||||
float max_travel = 0.0;
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Initialize step pin masks
|
||||
step_pin[idx] = get_step_pin_mask(idx);
|
||||
#ifdef COREXY
|
||||
if ((idx==A_MOTOR)||(idx==B_MOTOR)) { step_pin[idx] = (get_step_pin_mask(X_AXIS)|get_step_pin_mask(Y_AXIS)); }
|
||||
#endif
|
||||
|
||||
if (bit_istrue(cycle_mask,bit(idx))) {
|
||||
// Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
max_travel = max(max_travel,(-HOMING_AXIS_SEARCH_SCALAR)*settings.max_travel[idx]);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
step_pin_dual = (1<<DUAL_STEP_BIT);
|
||||
#endif
|
||||
|
||||
// Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
|
||||
bool approach = true;
|
||||
float homing_rate = settings.homing_seek_rate;
|
||||
|
||||
uint8_t limit_state, axislock, n_active_axis;
|
||||
do {
|
||||
|
||||
system_convert_array_steps_to_mpos(target,sys_position);
|
||||
|
||||
// Initialize and declare variables needed for homing routine.
|
||||
axislock = 0;
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
sys.homing_axis_lock_dual = 0;
|
||||
dual_trigger_position = 0;
|
||||
dual_axis_async_check = DUAL_AXIS_CHECK_DISABLE;
|
||||
#endif
|
||||
n_active_axis = 0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Set target location for active axes and setup computation for homing rate.
|
||||
if (bit_istrue(cycle_mask,bit(idx))) {
|
||||
n_active_axis++;
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = axis_position;
|
||||
sys_position[B_MOTOR] = -axis_position;
|
||||
} else if (idx == Y_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = sys_position[B_MOTOR] = axis_position;
|
||||
} else {
|
||||
sys_position[Z_AXIS] = 0;
|
||||
}
|
||||
#else
|
||||
sys_position[idx] = 0;
|
||||
#endif
|
||||
// Set target direction based on cycle mask and homing cycle approach state.
|
||||
// NOTE: This happens to compile smaller than any other implementation tried.
|
||||
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
|
||||
if (approach) { target[idx] = -max_travel; }
|
||||
else { target[idx] = max_travel; }
|
||||
} else {
|
||||
if (approach) { target[idx] = max_travel; }
|
||||
else { target[idx] = -max_travel; }
|
||||
int32_t dual_fail_distance = trunc(fail_distance * settings.steps_per_mm[DUAL_AXIS_SELECT]);
|
||||
// int32_t dual_fail_distance =
|
||||
// trunc((DUAL_AXIS_HOMING_TRIGGER_FAIL_DISTANCE)*settings.steps_per_mm[DUAL_AXIS_SELECT]);
|
||||
#endif
|
||||
float target[N_AXIS];
|
||||
float max_travel = 0.0;
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// Initialize step pin masks
|
||||
step_pin[idx] = get_step_pin_mask(idx);
|
||||
#ifdef COREXY
|
||||
if ((idx == A_MOTOR) || (idx == B_MOTOR)) {
|
||||
step_pin[idx] = (get_step_pin_mask(X_AXIS) | get_step_pin_mask(Y_AXIS));
|
||||
}
|
||||
// Apply axislock to the step port pins active in this cycle.
|
||||
axislock |= step_pin[idx];
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (idx == DUAL_AXIS_SELECT) { sys.homing_axis_lock_dual = step_pin_dual; }
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bit_istrue(cycle_mask, bit(idx))) {
|
||||
// Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
max_travel = max(max_travel, (-HOMING_AXIS_SEARCH_SCALAR) * settings.max_travel[idx]);
|
||||
}
|
||||
}
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
sys.homing_axis_lock = axislock;
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
step_pin_dual = (1 << DUAL_STEP_BIT);
|
||||
#endif
|
||||
|
||||
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
|
||||
pl_data->feed_rate = homing_rate; // Set current homing rate.
|
||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||
// Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
|
||||
bool approach = true;
|
||||
float homing_rate = settings.homing_seek_rate;
|
||||
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_SYS_MOTION; // Set to execute homing motion and clear existing flags.
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
uint8_t limit_state, axislock, n_active_axis;
|
||||
do {
|
||||
if (approach) {
|
||||
// Check limit state. Lock out cycle axes when they change.
|
||||
limit_state = limits_get_state();
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (axislock & step_pin[idx]) {
|
||||
if (limit_state & (1 << idx)) {
|
||||
#ifdef COREXY
|
||||
if (idx==Z_AXIS) { axislock &= ~(step_pin[Z_AXIS]); }
|
||||
else { axislock &= ~(step_pin[A_MOTOR]|step_pin[B_MOTOR]); }
|
||||
#else
|
||||
axislock &= ~(step_pin[idx]);
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (idx == DUAL_AXIS_SELECT) { dual_axis_async_check |= DUAL_AXIS_CHECK_TRIGGER_1; }
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
sys.homing_axis_lock = axislock;
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (sys.homing_axis_lock_dual) { // NOTE: Only true when homing dual axis.
|
||||
if (limit_state & (1 << N_AXIS)) {
|
||||
sys.homing_axis_lock_dual = 0;
|
||||
dual_axis_async_check |= DUAL_AXIS_CHECK_TRIGGER_2;
|
||||
}
|
||||
}
|
||||
|
||||
// When first dual axis limit triggers, record position and begin checking distance until other limit triggers. Bail upon failure.
|
||||
if (dual_axis_async_check) {
|
||||
if (dual_axis_async_check & DUAL_AXIS_CHECK_ENABLE) {
|
||||
if (( dual_axis_async_check & (DUAL_AXIS_CHECK_TRIGGER_1 | DUAL_AXIS_CHECK_TRIGGER_2)) == (DUAL_AXIS_CHECK_TRIGGER_1 | DUAL_AXIS_CHECK_TRIGGER_2)) {
|
||||
dual_axis_async_check = DUAL_AXIS_CHECK_DISABLE;
|
||||
} else {
|
||||
if (abs(dual_trigger_position - sys_position[DUAL_AXIS_SELECT]) > dual_fail_distance) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DUAL_APPROACH);
|
||||
mc_reset();
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
|
||||
system_convert_array_steps_to_mpos(target, sys_position);
|
||||
|
||||
// Initialize and declare variables needed for homing routine.
|
||||
axislock = 0;
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
sys.homing_axis_lock_dual = 0;
|
||||
dual_trigger_position = 0;
|
||||
dual_axis_async_check = DUAL_AXIS_CHECK_DISABLE;
|
||||
#endif
|
||||
n_active_axis = 0;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// Set target location for active axes and setup computation for homing rate.
|
||||
if (bit_istrue(cycle_mask, bit(idx))) {
|
||||
n_active_axis++;
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = axis_position;
|
||||
sys_position[B_MOTOR] = -axis_position;
|
||||
} else if (idx == Y_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = sys_position[B_MOTOR] = axis_position;
|
||||
} else {
|
||||
sys_position[Z_AXIS] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dual_axis_async_check |= DUAL_AXIS_CHECK_ENABLE;
|
||||
dual_trigger_position = sys_position[DUAL_AXIS_SELECT];
|
||||
#else
|
||||
sys_position[idx] = 0;
|
||||
#endif
|
||||
// Set target direction based on cycle mask and homing cycle approach state.
|
||||
// NOTE: This happens to compile smaller than any other implementation tried.
|
||||
if (bit_istrue(settings.homing_dir_mask, bit(idx))) {
|
||||
if (approach) {
|
||||
target[idx] = -max_travel;
|
||||
} else {
|
||||
target[idx] = max_travel;
|
||||
}
|
||||
} else {
|
||||
if (approach) {
|
||||
target[idx] = max_travel;
|
||||
} else {
|
||||
target[idx] = -max_travel;
|
||||
}
|
||||
}
|
||||
// Apply axislock to the step port pins active in this cycle.
|
||||
axislock |= step_pin[idx];
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (idx == DUAL_AXIS_SELECT) {
|
||||
sys.homing_axis_lock_dual = step_pin_dual;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
|
||||
// Exit routines: No time to run protocol_execute_realtime() in this loop.
|
||||
if (sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
|
||||
uint8_t rt_exec = sys_rt_exec_state;
|
||||
// Homing failure condition: Reset issued during cycle.
|
||||
if (rt_exec & EXEC_RESET) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
|
||||
// Homing failure condition: Safety door was opened.
|
||||
if (rt_exec & EXEC_SAFETY_DOOR) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DOOR); }
|
||||
// Homing failure condition: Limit switch still engaged after pull-off motion
|
||||
if (!approach && (limits_get_state() & cycle_mask)) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF); }
|
||||
// Homing failure condition: Limit switch not found during approach.
|
||||
if (approach && (rt_exec & EXEC_CYCLE_STOP)) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_APPROACH); }
|
||||
if (sys_rt_exec_alarm) {
|
||||
mc_reset(); // Stop motors, if they are running.
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
} else {
|
||||
// Pull-off motion complete. Disable CYCLE_STOP from executing.
|
||||
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
sys.homing_axis_lock = axislock;
|
||||
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
} while ((STEP_MASK & axislock) || (sys.homing_axis_lock_dual));
|
||||
#else
|
||||
} while (STEP_MASK & axislock);
|
||||
#endif
|
||||
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
|
||||
pl_data->feed_rate = homing_rate; // Set current homing rate.
|
||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||
|
||||
st_reset(); // Immediately force kill steppers and reset step segment buffer.
|
||||
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_SYS_MOTION; // Set to execute homing motion and clear existing flags.
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
do {
|
||||
if (approach) {
|
||||
// Check limit state. Lock out cycle axes when they change.
|
||||
limit_state = limits_get_state();
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (axislock & step_pin[idx]) {
|
||||
if (limit_state & (1 << idx)) {
|
||||
#ifdef COREXY
|
||||
if (idx == Z_AXIS) {
|
||||
axislock &= ~(step_pin[Z_AXIS]);
|
||||
} else {
|
||||
axislock &= ~(step_pin[A_MOTOR] | step_pin[B_MOTOR]);
|
||||
}
|
||||
#else
|
||||
axislock &= ~(step_pin[idx]);
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (idx == DUAL_AXIS_SELECT) {
|
||||
dual_axis_async_check |= DUAL_AXIS_CHECK_TRIGGER_1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
sys.homing_axis_lock = axislock;
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
if (sys.homing_axis_lock_dual) { // NOTE: Only true when homing dual axis.
|
||||
if (limit_state & (1 << N_AXIS)) {
|
||||
sys.homing_axis_lock_dual = 0;
|
||||
dual_axis_async_check |= DUAL_AXIS_CHECK_TRIGGER_2;
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse direction and reset homing rate for locate cycle(s).
|
||||
approach = !approach;
|
||||
// When first dual axis limit triggers, record position and begin checking distance until other limit
|
||||
// triggers. Bail upon failure.
|
||||
if (dual_axis_async_check) {
|
||||
if (dual_axis_async_check & DUAL_AXIS_CHECK_ENABLE) {
|
||||
if ((dual_axis_async_check & (DUAL_AXIS_CHECK_TRIGGER_1 | DUAL_AXIS_CHECK_TRIGGER_2)) ==
|
||||
(DUAL_AXIS_CHECK_TRIGGER_1 | DUAL_AXIS_CHECK_TRIGGER_2)) {
|
||||
dual_axis_async_check = DUAL_AXIS_CHECK_DISABLE;
|
||||
} else {
|
||||
if (abs(dual_trigger_position - sys_position[DUAL_AXIS_SELECT]) > dual_fail_distance) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DUAL_APPROACH);
|
||||
mc_reset();
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dual_axis_async_check |= DUAL_AXIS_CHECK_ENABLE;
|
||||
dual_trigger_position = sys_position[DUAL_AXIS_SELECT];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
|
||||
if (approach) {
|
||||
max_travel = settings.homing_pulloff*HOMING_AXIS_LOCATE_SCALAR;
|
||||
homing_rate = settings.homing_feed_rate;
|
||||
} else {
|
||||
max_travel = settings.homing_pulloff;
|
||||
homing_rate = settings.homing_seek_rate;
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
|
||||
// Exit routines: No time to run protocol_execute_realtime() in this loop.
|
||||
if (sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
|
||||
uint8_t rt_exec = sys_rt_exec_state;
|
||||
// Homing failure condition: Reset issued during cycle.
|
||||
if (rt_exec & EXEC_RESET) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
}
|
||||
// Homing failure condition: Safety door was opened.
|
||||
if (rt_exec & EXEC_SAFETY_DOOR) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DOOR);
|
||||
}
|
||||
// Homing failure condition: Limit switch still engaged after pull-off motion
|
||||
if (!approach && (limits_get_state() & cycle_mask)) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF);
|
||||
}
|
||||
// Homing failure condition: Limit switch not found during approach.
|
||||
if (approach && (rt_exec & EXEC_CYCLE_STOP)) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_APPROACH);
|
||||
}
|
||||
if (sys_rt_exec_alarm) {
|
||||
mc_reset(); // Stop motors, if they are running.
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
} else {
|
||||
// Pull-off motion complete. Disable CYCLE_STOP from executing.
|
||||
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
} while ((STEP_MASK & axislock) || (sys.homing_axis_lock_dual));
|
||||
#else
|
||||
} while (STEP_MASK & axislock);
|
||||
#endif
|
||||
|
||||
st_reset(); // Immediately force kill steppers and reset step segment buffer.
|
||||
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
|
||||
|
||||
// Reverse direction and reset homing rate for locate cycle(s).
|
||||
approach = !approach;
|
||||
|
||||
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
|
||||
if (approach) {
|
||||
max_travel = settings.homing_pulloff * HOMING_AXIS_LOCATE_SCALAR;
|
||||
homing_rate = settings.homing_feed_rate;
|
||||
} else {
|
||||
max_travel = settings.homing_pulloff;
|
||||
homing_rate = settings.homing_seek_rate;
|
||||
}
|
||||
|
||||
} while (n_cycle-- > 0);
|
||||
|
||||
// The active cycle axes should now be homed and machine limits have been located. By
|
||||
// default, Grbl defines machine space as all negative, as do most CNCs. Since limit switches
|
||||
// can be on either side of an axes, check and set axes machine zero appropriately. Also,
|
||||
// set up pull-off maneuver from axes limit switches that have been homed. This provides
|
||||
// some initial clearance off the switches and should also help prevent them from falsely
|
||||
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
|
||||
int32_t set_axis_position;
|
||||
// Set machine positions for homed limit switches. Don't update non-homed axes.
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
if (cycle_mask & bit(idx)) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
set_axis_position = 0;
|
||||
#else
|
||||
if (bit_istrue(settings.homing_dir_mask, bit(idx))) {
|
||||
set_axis_position =
|
||||
lround((settings.max_travel[idx] + settings.homing_pulloff) * settings.steps_per_mm[idx]);
|
||||
} else {
|
||||
set_axis_position = lround(-settings.homing_pulloff * settings.steps_per_mm[idx]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
|
||||
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
|
||||
} else if (idx == Y_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
|
||||
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
|
||||
} else {
|
||||
sys_position[idx] = set_axis_position;
|
||||
}
|
||||
#else
|
||||
sys_position[idx] = set_axis_position;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} while (n_cycle-- > 0);
|
||||
|
||||
// The active cycle axes should now be homed and machine limits have been located. By
|
||||
// default, Grbl defines machine space as all negative, as do most CNCs. Since limit switches
|
||||
// can be on either side of an axes, check and set axes machine zero appropriately. Also,
|
||||
// set up pull-off maneuver from axes limit switches that have been homed. This provides
|
||||
// some initial clearance off the switches and should also help prevent them from falsely
|
||||
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
|
||||
int32_t set_axis_position;
|
||||
// Set machine positions for homed limit switches. Don't update non-homed axes.
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
if (cycle_mask & bit(idx)) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
set_axis_position = 0;
|
||||
#else
|
||||
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
|
||||
set_axis_position = lround((settings.max_travel[idx]+settings.homing_pulloff)*settings.steps_per_mm[idx]);
|
||||
} else {
|
||||
set_axis_position = lround(-settings.homing_pulloff*settings.steps_per_mm[idx]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
|
||||
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
|
||||
} else if (idx==Y_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
|
||||
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
|
||||
} else {
|
||||
sys_position[idx] = set_axis_position;
|
||||
}
|
||||
#else
|
||||
sys_position[idx] = set_axis_position;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
|
||||
}
|
||||
|
||||
|
||||
// Performs a soft limit check. Called from mc_line() only. Assumes the machine has been homed,
|
||||
// the workspace volume is in all negative space, and the system is in normal operation.
|
||||
// NOTE: Used by jogging to limit travel within soft-limit volume.
|
||||
void limits_soft_check(float *target)
|
||||
{
|
||||
if (system_check_travel_limits(target)) {
|
||||
sys.soft_limit = true;
|
||||
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
|
||||
// workspace volume so just come to a controlled stop so position is not lost. When complete
|
||||
// enter alarm mode.
|
||||
if (sys.state == STATE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_FEED_HOLD);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) { return; }
|
||||
} while ( sys.state != STATE_IDLE );
|
||||
void limits_soft_check(float *target) {
|
||||
if (system_check_travel_limits(target)) {
|
||||
sys.soft_limit = true;
|
||||
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
|
||||
// workspace volume so just come to a controlled stop so position is not lost. When complete
|
||||
// enter alarm mode.
|
||||
if (sys.state == STATE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_FEED_HOLD);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) {
|
||||
return;
|
||||
}
|
||||
} while (sys.state != STATE_IDLE);
|
||||
}
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_SOFT_LIMIT); // Indicate soft limit critical event
|
||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||
return;
|
||||
}
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_SOFT_LIMIT); // Indicate soft limit critical event
|
||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#ifndef limits_h
|
||||
#define limits_h
|
||||
|
||||
|
||||
// Initialize the limits module
|
||||
void limits_init();
|
||||
|
||||
|
|
|
|||
138
grbl/main.c
138
grbl/main.c
|
|
@ -21,89 +21,89 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Declare system global variable structure
|
||||
system_t sys;
|
||||
int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
system_t sys;
|
||||
int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile uint8_t
|
||||
sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
volatile uint8_t
|
||||
sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
#ifdef DEBUG
|
||||
volatile uint8_t sys_rt_exec_debug;
|
||||
volatile uint8_t sys_rt_exec_debug;
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
// Initialize system upon power-up.
|
||||
serial_init(); // Setup serial baud rate and interrupts
|
||||
settings_init(); // Load Grbl settings from EEPROM
|
||||
stepper_init(); // Configure stepper pins and interrupt timers
|
||||
system_init(); // Configure pinout pins and pin-change interrupt
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Initialize system upon power-up.
|
||||
serial_init(); // Setup serial baud rate and interrupts
|
||||
settings_init(); // Load Grbl settings from EEPROM
|
||||
stepper_init(); // Configure stepper pins and interrupt timers
|
||||
system_init(); // Configure pinout pins and pin-change interrupt
|
||||
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
|
||||
sei(); // Enable interrupts
|
||||
|
||||
memset(sys_position,0,sizeof(sys_position)); // Clear machine position.
|
||||
sei(); // Enable interrupts
|
||||
|
||||
// Initialize system state.
|
||||
#ifdef FORCE_INITIALIZATION_ALARM
|
||||
// Force Grbl into an ALARM state upon a power-cycle or hard reset.
|
||||
// Initialize system state.
|
||||
#ifdef FORCE_INITIALIZATION_ALARM
|
||||
// Force Grbl into an ALARM state upon a power-cycle or hard reset.
|
||||
sys.state = STATE_ALARM;
|
||||
#else
|
||||
#else
|
||||
sys.state = STATE_IDLE;
|
||||
#endif
|
||||
|
||||
// Check for power-up and set system alarm if homing is enabled to force homing cycle
|
||||
// by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
|
||||
// startup scripts, but allows access to settings and internal commands. Only a homing
|
||||
// cycle '$H' or kill alarm locks '$X' will disable the alarm.
|
||||
// NOTE: The startup script will run after successful completion of the homing cycle, but
|
||||
// not after disabling the alarm locks. Prevents motion startup blocks from crashing into
|
||||
// things uncontrollably. Very bad.
|
||||
#ifdef HOMING_INIT_LOCK
|
||||
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Grbl initialization loop upon power-up or a system abort. For the latter, all processes
|
||||
// will return to this loop to be cleanly re-initialized.
|
||||
for(;;) {
|
||||
// Check for power-up and set system alarm if homing is enabled to force homing cycle
|
||||
// by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
|
||||
// startup scripts, but allows access to settings and internal commands. Only a homing
|
||||
// cycle '$H' or kill alarm locks '$X' will disable the alarm.
|
||||
// NOTE: The startup script will run after successful completion of the homing cycle, but
|
||||
// not after disabling the alarm locks. Prevents motion startup blocks from crashing into
|
||||
// things uncontrollably. Very bad.
|
||||
#ifdef HOMING_INIT_LOCK
|
||||
if (bit_istrue(settings.flags, BITFLAG_HOMING_ENABLE)) {
|
||||
sys.state = STATE_ALARM;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reset system variables.
|
||||
uint8_t prior_state = sys.state;
|
||||
memset(&sys, 0, sizeof(system_t)); // Clear system struct variable.
|
||||
sys.state = prior_state;
|
||||
sys.f_override = DEFAULT_FEED_OVERRIDE; // Set to 100%
|
||||
sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
|
||||
sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
|
||||
memset(sys_probe_position,0,sizeof(sys_probe_position)); // Clear probe position.
|
||||
sys_probe_state = 0;
|
||||
sys_rt_exec_state = 0;
|
||||
sys_rt_exec_alarm = 0;
|
||||
sys_rt_exec_motion_override = 0;
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
// Grbl initialization loop upon power-up or a system abort. For the latter, all processes
|
||||
// will return to this loop to be cleanly re-initialized.
|
||||
for (;;) {
|
||||
|
||||
// Reset Grbl primary systems.
|
||||
serial_reset_read_buffer(); // Clear serial read buffer
|
||||
gc_init(); // Set g-code parser to default state
|
||||
spindle_init();
|
||||
coolant_init();
|
||||
limits_init();
|
||||
probe_init();
|
||||
plan_reset(); // Clear block buffer and planner variables
|
||||
st_reset(); // Clear stepper subsystem variables.
|
||||
// Reset system variables.
|
||||
uint8_t prior_state = sys.state;
|
||||
memset(&sys, 0, sizeof(system_t)); // Clear system struct variable.
|
||||
sys.state = prior_state;
|
||||
sys.f_override = DEFAULT_FEED_OVERRIDE; // Set to 100%
|
||||
sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
|
||||
sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
|
||||
memset(sys_probe_position, 0, sizeof(sys_probe_position)); // Clear probe position.
|
||||
sys_probe_state = 0;
|
||||
sys_rt_exec_state = 0;
|
||||
sys_rt_exec_alarm = 0;
|
||||
sys_rt_exec_motion_override = 0;
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
|
||||
// Sync cleared gcode and planner positions to current system position.
|
||||
plan_sync_position();
|
||||
gc_sync_position();
|
||||
// Reset Grbl primary systems.
|
||||
serial_reset_read_buffer(); // Clear serial read buffer
|
||||
gc_init(); // Set g-code parser to default state
|
||||
spindle_init();
|
||||
coolant_init();
|
||||
limits_init();
|
||||
probe_init();
|
||||
plan_reset(); // Clear block buffer and planner variables
|
||||
st_reset(); // Clear stepper subsystem variables.
|
||||
|
||||
// Print welcome message. Indicates an initialization has occured at power-up or with a reset.
|
||||
report_init_message();
|
||||
// Sync cleared gcode and planner positions to current system position.
|
||||
plan_sync_position();
|
||||
gc_sync_position();
|
||||
|
||||
// Start Grbl main loop. Processes program inputs and executes them.
|
||||
protocol_main_loop();
|
||||
// Print welcome message. Indicates an initialization has occured at power-up or with a reset.
|
||||
report_init_message();
|
||||
|
||||
}
|
||||
return 0; /* Never reached */
|
||||
// Start Grbl main loop. Processes program inputs and executes them.
|
||||
protocol_main_loop();
|
||||
}
|
||||
return 0; /* Never reached */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||
// (1 minute)/feed_rate time.
|
||||
|
|
@ -29,53 +28,61 @@
|
|||
// segments, must pass through this routine before being passed to the planner. The seperation of
|
||||
// mc_line and plan_buffer_line is done primarily to place non-planner-type functions from being
|
||||
// in the planner and to let backlash compensation or canned cycle integration simple and direct.
|
||||
void mc_line(float *target, plan_line_data_t *pl_data)
|
||||
{
|
||||
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
||||
// from everywhere in Grbl.
|
||||
if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
// NOTE: Block jog state. Jogging is a special case and soft limits are handled independently.
|
||||
if (sys.state != STATE_JOG) { limits_soft_check(target); }
|
||||
}
|
||||
|
||||
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
|
||||
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
||||
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
||||
// plan_check_full_buffer() and check for system abort loop. Also for position reporting
|
||||
// backlash steps will need to be also tracked, which will need to be kept at a system level.
|
||||
// There are likely some other things that will need to be tracked as well. However, we feel
|
||||
// that backlash compensation should NOT be handled by Grbl itself, because there are a myriad
|
||||
// of ways to implement it and can be effective or ineffective for different CNC machines. This
|
||||
// would be better handled by the interface as a post-processor task, where the original g-code
|
||||
// is translated and inserts backlash motions that best suits the machine.
|
||||
// NOTE: Perhaps as a middle-ground, all that needs to be sent is a flag or special command that
|
||||
// indicates to Grbl what is a backlash compensation motion, so that Grbl executes the move but
|
||||
// doesn't update the machine position values. Since the position values used by the g-code
|
||||
// parser and planner are separate from the system machine positions, this is doable.
|
||||
|
||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||
// Remain in this loop until there is room in the buffer.
|
||||
do {
|
||||
protocol_execute_realtime(); // Check for any run-time commands
|
||||
if (sys.abort) { return; } // Bail, if system abort.
|
||||
if ( plan_check_full_buffer() ) { protocol_auto_cycle_start(); } // Auto-cycle start when buffer is full.
|
||||
else { break; }
|
||||
} while (1);
|
||||
|
||||
// Plan and queue motion into planner buffer
|
||||
if (plan_buffer_line(target, pl_data) == PLAN_EMPTY_BLOCK) {
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
// Correctly set spindle state, if there is a coincident position passed. Forces a buffer
|
||||
// sync while in M3 laser mode only.
|
||||
if (pl_data->condition & PL_COND_FLAG_SPINDLE_CW) {
|
||||
spindle_sync(PL_COND_FLAG_SPINDLE_CW, pl_data->spindle_speed);
|
||||
}
|
||||
void mc_line(float *target, plan_line_data_t *pl_data) {
|
||||
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
||||
// from everywhere in Grbl.
|
||||
if (bit_istrue(settings.flags, BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
// NOTE: Block jog state. Jogging is a special case and soft limits are handled independently.
|
||||
if (sys.state != STATE_JOG) {
|
||||
limits_soft_check(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
||||
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
||||
// plan_check_full_buffer() and check for system abort loop. Also for position reporting
|
||||
// backlash steps will need to be also tracked, which will need to be kept at a system level.
|
||||
// There are likely some other things that will need to be tracked as well. However, we feel
|
||||
// that backlash compensation should NOT be handled by Grbl itself, because there are a myriad
|
||||
// of ways to implement it and can be effective or ineffective for different CNC machines. This
|
||||
// would be better handled by the interface as a post-processor task, where the original g-code
|
||||
// is translated and inserts backlash motions that best suits the machine.
|
||||
// NOTE: Perhaps as a middle-ground, all that needs to be sent is a flag or special command that
|
||||
// indicates to Grbl what is a backlash compensation motion, so that Grbl executes the move but
|
||||
// doesn't update the machine position values. Since the position values used by the g-code
|
||||
// parser and planner are separate from the system machine positions, this is doable.
|
||||
|
||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||
// Remain in this loop until there is room in the buffer.
|
||||
do {
|
||||
protocol_execute_realtime(); // Check for any run-time commands
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Bail, if system abort.
|
||||
if (plan_check_full_buffer()) {
|
||||
protocol_auto_cycle_start();
|
||||
} // Auto-cycle start when buffer is full.
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
// Plan and queue motion into planner buffer
|
||||
if (plan_buffer_line(target, pl_data) == PLAN_EMPTY_BLOCK) {
|
||||
if (bit_istrue(settings.flags, BITFLAG_LASER_MODE)) {
|
||||
// Correctly set spindle state, if there is a coincident position passed. Forces a buffer
|
||||
// sync while in M3 laser mode only.
|
||||
if (pl_data->condition & PL_COND_FLAG_SPINDLE_CW) {
|
||||
spindle_sync(PL_COND_FLAG_SPINDLE_CW, pl_data->spindle_speed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
|
||||
|
|
@ -84,305 +91,327 @@ void mc_line(float *target, plan_line_data_t *pl_data)
|
|||
// The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance
|
||||
// of each segment is configured in settings.arc_tolerance, which is defined to be the maximum normal
|
||||
// distance from segment to the circle when the end points both lie on the circle.
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc)
|
||||
{
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
float center_axis1 = position[axis_1] + offset[axis_1];
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius, uint8_t axis_0,
|
||||
uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc) {
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
float center_axis1 = position[axis_1] + offset[axis_1];
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) { angular_travel -= 2*M_PI; }
|
||||
} else {
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON) { angular_travel += 2*M_PI; }
|
||||
}
|
||||
|
||||
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
|
||||
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
|
||||
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
|
||||
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
|
||||
uint16_t segments = floor(fabs(0.5*angular_travel*radius)/
|
||||
sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
|
||||
|
||||
if (segments) {
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
// all segments.
|
||||
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
|
||||
pl_data->feed_rate *= segments;
|
||||
bit_false(pl_data->condition,PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2(r_axis0 * rt_axis1 - r_axis1 * rt_axis0, r_axis0 * rt_axis0 + r_axis1 * rt_axis1);
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) {
|
||||
angular_travel -= 2 * M_PI;
|
||||
}
|
||||
} else {
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON) {
|
||||
angular_travel += 2 * M_PI;
|
||||
}
|
||||
}
|
||||
|
||||
float theta_per_segment = angular_travel/segments;
|
||||
float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments;
|
||||
|
||||
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
|
||||
and phi is the angle of rotation. Solution approach by Jens Geisler.
|
||||
r_T = [cos(phi) -sin(phi);
|
||||
sin(phi) cos(phi] * r ;
|
||||
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
|
||||
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
|
||||
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
|
||||
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
|
||||
uint16_t segments = floor(fabs(0.5 * angular_travel * radius) /
|
||||
sqrt(settings.arc_tolerance * (2 * radius - settings.arc_tolerance)));
|
||||
|
||||
For arc generation, the center of the circle is the axis of rotation and the radius vector is
|
||||
defined from the circle center to the initial position. Each line segment is formed by successive
|
||||
vector rotations. Single precision values can accumulate error greater than tool precision in rare
|
||||
cases. So, exact arc path correction is implemented. This approach avoids the problem of too many very
|
||||
expensive trig operations [sin(),cos(),tan()] which can take 100-200 usec each to compute.
|
||||
if (segments) {
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
// all segments.
|
||||
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
|
||||
pl_data->feed_rate *= segments;
|
||||
bit_false(pl_data->condition, PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
|
||||
}
|
||||
|
||||
Small angle approximation may be used to reduce computation overhead further. A third-order approximation
|
||||
(second order sin() has too much error) holds for most, if not, all CNC applications. Note that this
|
||||
approximation will begin to accumulate a numerical drift error when theta_per_segment is greater than
|
||||
~0.25 rad(14 deg) AND the approximation is successively used without correction several dozen times. This
|
||||
scenario is extremely unlikely, since segment lengths and theta_per_segment are automatically generated
|
||||
and scaled by the arc tolerance setting. Only a very large arc tolerance setting, unrealistic for CNC
|
||||
applications, would cause this numerical drift error. However, it is best to set N_ARC_CORRECTION from a
|
||||
low of ~4 to a high of ~20 or so to avoid trig operations while keeping arc generation accurate.
|
||||
float theta_per_segment = angular_travel / segments;
|
||||
float linear_per_segment = (target[axis_linear] - position[axis_linear]) / segments;
|
||||
|
||||
This approximation also allows mc_arc to immediately insert a line segment into the planner
|
||||
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
|
||||
a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead.
|
||||
This is important when there are successive arc motions.
|
||||
*/
|
||||
// Computes: cos_T = 1 - theta_per_segment^2/2, sin_T = theta_per_segment - theta_per_segment^3/6) in ~52usec
|
||||
float cos_T = 2.0 - theta_per_segment*theta_per_segment;
|
||||
float sin_T = theta_per_segment*0.16666667*(cos_T + 4.0);
|
||||
cos_T *= 0.5;
|
||||
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
|
||||
and phi is the angle of rotation. Solution approach by Jens Geisler.
|
||||
r_T = [cos(phi) -sin(phi);
|
||||
sin(phi) cos(phi] * r ;
|
||||
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
uint16_t i;
|
||||
uint8_t count = 0;
|
||||
For arc generation, the center of the circle is the axis of rotation and the radius vector is
|
||||
defined from the circle center to the initial position. Each line segment is formed by successive
|
||||
vector rotations. Single precision values can accumulate error greater than tool precision in rare
|
||||
cases. So, exact arc path correction is implemented. This approach avoids the problem of too many very
|
||||
expensive trig operations [sin(),cos(),tan()] which can take 100-200 usec each to compute.
|
||||
|
||||
for (i = 1; i<segments; i++) { // Increment (segments-1).
|
||||
Small angle approximation may be used to reduce computation overhead further. A third-order approximation
|
||||
(second order sin() has too much error) holds for most, if not, all CNC applications. Note that this
|
||||
approximation will begin to accumulate a numerical drift error when theta_per_segment is greater than
|
||||
~0.25 rad(14 deg) AND the approximation is successively used without correction several dozen times. This
|
||||
scenario is extremely unlikely, since segment lengths and theta_per_segment are automatically generated
|
||||
and scaled by the arc tolerance setting. Only a very large arc tolerance setting, unrealistic for CNC
|
||||
applications, would cause this numerical drift error. However, it is best to set N_ARC_CORRECTION from a
|
||||
low of ~4 to a high of ~20 or so to avoid trig operations while keeping arc generation accurate.
|
||||
|
||||
if (count < N_ARC_CORRECTION) {
|
||||
// Apply vector rotation matrix. ~40 usec
|
||||
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
|
||||
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
|
||||
r_axis1 = r_axisi;
|
||||
count++;
|
||||
} else {
|
||||
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
|
||||
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
|
||||
cos_Ti = cos(i*theta_per_segment);
|
||||
sin_Ti = sin(i*theta_per_segment);
|
||||
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
|
||||
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
|
||||
count = 0;
|
||||
}
|
||||
This approximation also allows mc_arc to immediately insert a line segment into the planner
|
||||
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
|
||||
a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead.
|
||||
This is important when there are successive arc motions.
|
||||
*/
|
||||
// Computes: cos_T = 1 - theta_per_segment^2/2, sin_T = theta_per_segment - theta_per_segment^3/6) in ~52usec
|
||||
float cos_T = 2.0 - theta_per_segment * theta_per_segment;
|
||||
float sin_T = theta_per_segment * 0.16666667 * (cos_T + 4.0);
|
||||
cos_T *= 0.5;
|
||||
|
||||
// Update arc_target location
|
||||
position[axis_0] = center_axis0 + r_axis0;
|
||||
position[axis_1] = center_axis1 + r_axis1;
|
||||
position[axis_linear] += linear_per_segment;
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
uint16_t i;
|
||||
uint8_t count = 0;
|
||||
|
||||
mc_line(position, pl_data);
|
||||
for (i = 1; i < segments; i++) { // Increment (segments-1).
|
||||
|
||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||
if (sys.abort) { return; }
|
||||
if (count < N_ARC_CORRECTION) {
|
||||
// Apply vector rotation matrix. ~40 usec
|
||||
r_axisi = r_axis0 * sin_T + r_axis1 * cos_T;
|
||||
r_axis0 = r_axis0 * cos_T - r_axis1 * sin_T;
|
||||
r_axis1 = r_axisi;
|
||||
count++;
|
||||
} else {
|
||||
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
|
||||
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
|
||||
cos_Ti = cos(i * theta_per_segment);
|
||||
sin_Ti = sin(i * theta_per_segment);
|
||||
r_axis0 = -offset[axis_0] * cos_Ti + offset[axis_1] * sin_Ti;
|
||||
r_axis1 = -offset[axis_0] * sin_Ti - offset[axis_1] * cos_Ti;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// Update arc_target location
|
||||
position[axis_0] = center_axis0 + r_axis0;
|
||||
position[axis_1] = center_axis1 + r_axis1;
|
||||
position[axis_linear] += linear_per_segment;
|
||||
|
||||
mc_line(position, pl_data);
|
||||
|
||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||
if (sys.abort) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure last segment arrives at target location.
|
||||
mc_line(target, pl_data);
|
||||
// Ensure last segment arrives at target location.
|
||||
mc_line(target, pl_data);
|
||||
}
|
||||
|
||||
|
||||
// Execute dwell in seconds.
|
||||
void mc_dwell(float seconds)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
protocol_buffer_synchronize();
|
||||
delay_sec(seconds, DELAY_MODE_DWELL);
|
||||
void mc_dwell(float seconds) {
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
protocol_buffer_synchronize();
|
||||
delay_sec(seconds, DELAY_MODE_DWELL);
|
||||
}
|
||||
|
||||
|
||||
// Perform homing cycle to locate and set machine zero. Only '$H' executes this command.
|
||||
// NOTE: There should be no motions in the buffer and Grbl must be in an idle state before
|
||||
// executing the homing cycle. This prevents incorrect buffered plans after homing.
|
||||
void mc_homing_cycle(uint8_t cycle_mask)
|
||||
{
|
||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||
// with machines with limits wired on both ends of travel to one limit pin.
|
||||
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
|
||||
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
|
||||
void mc_homing_cycle(uint8_t cycle_mask) {
|
||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||
// with machines with limits wired on both ends of travel to one limit pin.
|
||||
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
|
||||
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT);
|
||||
return;
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
limits_disable(); // Disable hard limits pin change register for cycle duration
|
||||
limits_disable(); // Disable hard limits pin change register for cycle duration
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Perform homing routine. NOTE: Special motion case. Only system reset works.
|
||||
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
if (cycle_mask) { limits_go_home(cycle_mask); } // Perform homing cycle based on mask.
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Perform homing routine. NOTE: Special motion case. Only system reset works.
|
||||
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
if (cycle_mask) {
|
||||
limits_go_home(cycle_mask);
|
||||
} // Perform homing cycle based on mask.
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Search to engage all axes limit switches at faster homing seek rate.
|
||||
limits_go_home(HOMING_CYCLE_0); // Homing cycle 0
|
||||
#ifdef HOMING_CYCLE_1
|
||||
limits_go_home(HOMING_CYCLE_1); // Homing cycle 1
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_2
|
||||
limits_go_home(HOMING_CYCLE_2); // Homing cycle 2
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
{
|
||||
// Search to engage all axes limit switches at faster homing seek rate.
|
||||
limits_go_home(HOMING_CYCLE_0); // Homing cycle 0
|
||||
#ifdef HOMING_CYCLE_1
|
||||
limits_go_home(HOMING_CYCLE_1); // Homing cycle 1
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_2
|
||||
limits_go_home(HOMING_CYCLE_2); // Homing cycle 2
|
||||
#endif
|
||||
}
|
||||
|
||||
protocol_execute_realtime(); // Check for reset and set system abort.
|
||||
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
|
||||
protocol_execute_realtime(); // Check for reset and set system abort.
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Did not complete. Alarm state set by mc_alarm.
|
||||
|
||||
// Homing cycle complete! Setup system for normal operation.
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Homing cycle complete! Setup system for normal operation.
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
// Sync gcode parser and planner positions to homed position.
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
// Sync gcode parser and planner positions to homed position.
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
|
||||
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
|
||||
limits_init();
|
||||
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
|
||||
limits_init();
|
||||
}
|
||||
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
|
||||
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags)
|
||||
{
|
||||
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
|
||||
if (sys.state == STATE_CHECK_MODE) { return(GC_PROBE_CHECK_MODE); }
|
||||
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags) {
|
||||
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return (GC_PROBE_CHECK_MODE);
|
||||
}
|
||||
|
||||
// Finish all queued commands and empty planner buffer before starting probe cycle.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Return if system reset has been issued.
|
||||
// Finish all queued commands and empty planner buffer before starting probe cycle.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) {
|
||||
return (GC_PROBE_ABORT);
|
||||
} // Return if system reset has been issued.
|
||||
|
||||
// Initialize probing control variables
|
||||
uint8_t is_probe_away = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_AWAY);
|
||||
uint8_t is_no_error = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_NO_ERROR);
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
probe_configure_invert_mask(is_probe_away);
|
||||
// Initialize probing control variables
|
||||
uint8_t is_probe_away = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_AWAY);
|
||||
uint8_t is_no_error = bit_istrue(parser_flags, GC_PARSER_PROBE_IS_NO_ERROR);
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
probe_configure_invert_mask(is_probe_away);
|
||||
|
||||
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
|
||||
// NOTE: This probe initialization error applies to all probing cycles.
|
||||
if ( probe_get_state() ) { // Check probe pin state.
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
|
||||
protocol_execute_realtime();
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return(GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
}
|
||||
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
|
||||
// NOTE: This probe initialization error applies to all probing cycles.
|
||||
if (probe_get_state()) { // Check probe pin state.
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
|
||||
protocol_execute_realtime();
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return (GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
}
|
||||
|
||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||
mc_line(target, pl_data);
|
||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||
mc_line(target, pl_data);
|
||||
|
||||
// Activate the probing state monitor in the stepper module.
|
||||
sys_probe_state = PROBE_ACTIVE;
|
||||
// Activate the probing state monitor in the stepper module.
|
||||
sys_probe_state = PROBE_ACTIVE;
|
||||
|
||||
// Perform probing cycle. Wait here until probe is triggered or motion completes.
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Check for system abort
|
||||
} while (sys.state != STATE_IDLE);
|
||||
// Perform probing cycle. Wait here until probe is triggered or motion completes.
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) {
|
||||
return (GC_PROBE_ABORT);
|
||||
} // Check for system abort
|
||||
} while (sys.state != STATE_IDLE);
|
||||
|
||||
// Probing cycle complete!
|
||||
// Probing cycle complete!
|
||||
|
||||
// Set state variables and error out, if the probe failed and cycle with error is enabled.
|
||||
if (sys_probe_state == PROBE_ACTIVE) {
|
||||
if (is_no_error) { memcpy(sys_probe_position, sys_position, sizeof(sys_position)); }
|
||||
else { system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_CONTACT); }
|
||||
} else {
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
}
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
// Set state variables and error out, if the probe failed and cycle with error is enabled.
|
||||
if (sys_probe_state == PROBE_ACTIVE) {
|
||||
if (is_no_error) {
|
||||
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
} else {
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_CONTACT);
|
||||
}
|
||||
} else {
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
}
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
plan_sync_position(); // Sync planner position to current machine position.
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
plan_sync_position(); // Sync planner position to current machine position.
|
||||
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
report_probe_parameters();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (sys.probe_succeeded) { return(GC_PROBE_FOUND); } // Successful probe cycle.
|
||||
else { return(GC_PROBE_FAIL_END); } // Failed to trigger probe within travel. With or without error.
|
||||
if (sys.probe_succeeded) {
|
||||
return (GC_PROBE_FOUND);
|
||||
} // Successful probe cycle.
|
||||
else {
|
||||
return (GC_PROBE_FAIL_END);
|
||||
} // Failed to trigger probe within travel. With or without error.
|
||||
}
|
||||
|
||||
|
||||
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
|
||||
// NOTE: Uses the always free planner ring buffer head to store motion parameters for execution.
|
||||
#ifdef PARKING_ENABLE
|
||||
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data)
|
||||
{
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data) {
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Block during abort.
|
||||
|
||||
uint8_t plan_status = plan_buffer_line(parking_target, pl_data);
|
||||
|
||||
if (plan_status) {
|
||||
bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
|
||||
st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
|
||||
st_prep_buffer();
|
||||
st_wake_up();
|
||||
do {
|
||||
protocol_exec_rt_system();
|
||||
if (sys.abort) { return; }
|
||||
} while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
|
||||
bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
bit_false(sys.step_control,
|
||||
STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
|
||||
st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
|
||||
st_prep_buffer();
|
||||
st_wake_up();
|
||||
do {
|
||||
protocol_exec_rt_system();
|
||||
if (sys.abort) {
|
||||
return;
|
||||
}
|
||||
} while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
|
||||
} else {
|
||||
bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
protocol_exec_rt_system();
|
||||
bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
protocol_exec_rt_system();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
void mc_override_ctrl_update(uint8_t override_state)
|
||||
{
|
||||
void mc_override_ctrl_update(uint8_t override_state) {
|
||||
// Finish all queued commands before altering override control state
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) { return; }
|
||||
if (sys.abort) {
|
||||
return;
|
||||
}
|
||||
sys.override_ctrl = override_state;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Method to ready the system to reset by setting the realtime reset command and killing any
|
||||
// active processes in the system. This also checks if a system reset is issued while Grbl
|
||||
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
|
||||
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
|
||||
// realtime abort command and hard limits. So, keep to a minimum.
|
||||
void mc_reset()
|
||||
{
|
||||
// Only this function can set the system reset. Helps prevent multiple kill calls.
|
||||
if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
|
||||
system_set_exec_state_flag(EXEC_RESET);
|
||||
void mc_reset() {
|
||||
// Only this function can set the system reset. Helps prevent multiple kill calls.
|
||||
if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
|
||||
system_set_exec_state_flag(EXEC_RESET);
|
||||
|
||||
// Kill spindle and coolant.
|
||||
spindle_stop();
|
||||
coolant_stop();
|
||||
// Kill spindle and coolant.
|
||||
spindle_stop();
|
||||
coolant_stop();
|
||||
|
||||
// Kill steppers only if in any motion state, i.e. cycle, actively holding, or homing.
|
||||
// NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
|
||||
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
|
||||
// violated, by which, all bets are off.
|
||||
if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
|
||||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
|
||||
if (sys.state == STATE_HOMING) {
|
||||
if (!sys_rt_exec_alarm) {system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
|
||||
} else { system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE); }
|
||||
st_go_idle(); // Force kill steppers. Position has likely been lost.
|
||||
// Kill steppers only if in any motion state, i.e. cycle, actively holding, or homing.
|
||||
// NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
|
||||
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
|
||||
// violated, by which, all bets are off.
|
||||
if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
|
||||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
|
||||
if (sys.state == STATE_HOMING) {
|
||||
if (!sys_rt_exec_alarm) {
|
||||
system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET);
|
||||
}
|
||||
} else {
|
||||
system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE);
|
||||
}
|
||||
st_go_idle(); // Force kill steppers. Position has likely been lost.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,16 +22,14 @@
|
|||
#ifndef motion_control_h
|
||||
#define motion_control_h
|
||||
|
||||
|
||||
// System motion commands must have a line number of zero.
|
||||
#define HOMING_CYCLE_LINE_NUMBER 0
|
||||
#define HOMING_CYCLE_LINE_NUMBER 0
|
||||
#define PARKING_MOTION_LINE_NUMBER 0
|
||||
|
||||
#define HOMING_CYCLE_ALL 0 // Must be zero.
|
||||
#define HOMING_CYCLE_X bit(X_AXIS)
|
||||
#define HOMING_CYCLE_Y bit(Y_AXIS)
|
||||
#define HOMING_CYCLE_Z bit(Z_AXIS)
|
||||
|
||||
#define HOMING_CYCLE_ALL 0 // Must be zero.
|
||||
#define HOMING_CYCLE_X bit(X_AXIS)
|
||||
#define HOMING_CYCLE_Y bit(Y_AXIS)
|
||||
#define HOMING_CYCLE_Z bit(Z_AXIS)
|
||||
|
||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||
|
|
@ -42,8 +40,8 @@ void mc_line(float *target, plan_line_data_t *pl_data);
|
|||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc);
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius, uint8_t axis_0,
|
||||
uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc);
|
||||
|
||||
// Dwell for a specific number of seconds
|
||||
void mc_dwell(float seconds);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
|
||||
|
||||
|
||||
// Extracts a floating point value from a string. The following code is based loosely on
|
||||
// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
|
||||
// available conversion method examples, but has been highly optimized for Grbl. For known
|
||||
|
|
@ -32,159 +30,163 @@
|
|||
// Scientific notation is officially not supported by g-code, and the 'E' character may
|
||||
// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
|
||||
// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
|
||||
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
|
||||
{
|
||||
char *ptr = line + *char_counter;
|
||||
unsigned char c;
|
||||
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr) {
|
||||
char *ptr = line + *char_counter;
|
||||
unsigned char c;
|
||||
|
||||
// Grab first character and increment pointer. No spaces assumed in line.
|
||||
c = *ptr++;
|
||||
|
||||
// Capture initial positive/minus character
|
||||
bool isnegative = false;
|
||||
if (c == '-') {
|
||||
isnegative = true;
|
||||
// Grab first character and increment pointer. No spaces assumed in line.
|
||||
c = *ptr++;
|
||||
} else if (c == '+') {
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Extract number into fast integer. Track decimal in terms of exponent value.
|
||||
uint32_t intval = 0;
|
||||
int8_t exp = 0;
|
||||
uint8_t ndigit = 0;
|
||||
bool isdecimal = false;
|
||||
while(1) {
|
||||
c -= '0';
|
||||
if (c <= 9) {
|
||||
ndigit++;
|
||||
if (ndigit <= MAX_INT_DIGITS) {
|
||||
if (isdecimal) { exp--; }
|
||||
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
|
||||
} else {
|
||||
if (!(isdecimal)) { exp++; } // Drop overflow digits
|
||||
}
|
||||
} else if (c == (('.'-'0') & 0xff) && !(isdecimal)) {
|
||||
isdecimal = true;
|
||||
// Capture initial positive/minus character
|
||||
bool isnegative = false;
|
||||
if (c == '-') {
|
||||
isnegative = true;
|
||||
c = *ptr++;
|
||||
} else if (c == '+') {
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Extract number into fast integer. Track decimal in terms of exponent value.
|
||||
uint32_t intval = 0;
|
||||
int8_t exp = 0;
|
||||
uint8_t ndigit = 0;
|
||||
bool isdecimal = false;
|
||||
while (1) {
|
||||
c -= '0';
|
||||
if (c <= 9) {
|
||||
ndigit++;
|
||||
if (ndigit <= MAX_INT_DIGITS) {
|
||||
if (isdecimal) {
|
||||
exp--;
|
||||
}
|
||||
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
|
||||
} else {
|
||||
if (!(isdecimal)) {
|
||||
exp++;
|
||||
} // Drop overflow digits
|
||||
}
|
||||
} else if (c == (('.' - '0') & 0xff) && !(isdecimal)) {
|
||||
isdecimal = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Return if no digits have been read.
|
||||
if (!ndigit) {
|
||||
return (false);
|
||||
};
|
||||
|
||||
// Convert integer into floating point.
|
||||
float fval;
|
||||
fval = (float)intval;
|
||||
|
||||
// Apply decimal. Should perform no more than two floating point multiplications for the
|
||||
// expected range of E0 to E-4.
|
||||
if (fval != 0) {
|
||||
while (exp <= -2) {
|
||||
fval *= 0.01;
|
||||
exp += 2;
|
||||
}
|
||||
if (exp < 0) {
|
||||
fval *= 0.1;
|
||||
} else if (exp > 0) {
|
||||
do {
|
||||
fval *= 10.0;
|
||||
} while (--exp > 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign floating point value with correct sign.
|
||||
if (isnegative) {
|
||||
*float_ptr = -fval;
|
||||
} else {
|
||||
break;
|
||||
*float_ptr = fval;
|
||||
}
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Return if no digits have been read.
|
||||
if (!ndigit) { return(false); };
|
||||
*char_counter = ptr - line - 1; // Set char_counter to next statement
|
||||
|
||||
// Convert integer into floating point.
|
||||
float fval;
|
||||
fval = (float)intval;
|
||||
|
||||
// Apply decimal. Should perform no more than two floating point multiplications for the
|
||||
// expected range of E0 to E-4.
|
||||
if (fval != 0) {
|
||||
while (exp <= -2) {
|
||||
fval *= 0.01;
|
||||
exp += 2;
|
||||
}
|
||||
if (exp < 0) {
|
||||
fval *= 0.1;
|
||||
} else if (exp > 0) {
|
||||
do {
|
||||
fval *= 10.0;
|
||||
} while (--exp > 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign floating point value with correct sign.
|
||||
if (isnegative) {
|
||||
*float_ptr = -fval;
|
||||
} else {
|
||||
*float_ptr = fval;
|
||||
}
|
||||
|
||||
*char_counter = ptr - line - 1; // Set char_counter to next statement
|
||||
|
||||
return(true);
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// Non-blocking delay function used for general operation and suspend features.
|
||||
void delay_sec(float seconds, uint8_t mode)
|
||||
{
|
||||
uint16_t i = ceil(1000/DWELL_TIME_STEP*seconds);
|
||||
while (i-- > 0) {
|
||||
if (sys.abort) { return; }
|
||||
if (mode == DELAY_MODE_DWELL) {
|
||||
protocol_execute_realtime();
|
||||
} else { // DELAY_MODE_SYS_SUSPEND
|
||||
// Execute rt_system() only to avoid nesting suspend loops.
|
||||
protocol_exec_rt_system();
|
||||
if (sys.suspend & SUSPEND_RESTART_RETRACT) { return; } // Bail, if safety door reopens.
|
||||
}
|
||||
_delay_ms(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
|
||||
}
|
||||
void delay_sec(float seconds, uint8_t mode) {
|
||||
uint16_t i = ceil(1000 / DWELL_TIME_STEP * seconds);
|
||||
while (i-- > 0) {
|
||||
if (sys.abort) {
|
||||
return;
|
||||
}
|
||||
if (mode == DELAY_MODE_DWELL) {
|
||||
protocol_execute_realtime();
|
||||
} else { // DELAY_MODE_SYS_SUSPEND
|
||||
// Execute rt_system() only to avoid nesting suspend loops.
|
||||
protocol_exec_rt_system();
|
||||
if (sys.suspend & SUSPEND_RESTART_RETRACT) {
|
||||
return;
|
||||
} // Bail, if safety door reopens.
|
||||
}
|
||||
_delay_ms(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delays variable defined milliseconds. Compiler compatibility fix for _delay_ms(),
|
||||
// which only accepts constants in future compiler releases.
|
||||
void delay_ms(uint16_t ms)
|
||||
{
|
||||
while ( ms-- ) { _delay_ms(1); }
|
||||
void delay_ms(uint16_t ms) {
|
||||
while (ms--) {
|
||||
_delay_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Delays variable defined microseconds. Compiler compatibility fix for _delay_us(),
|
||||
// which only accepts constants in future compiler releases. Written to perform more
|
||||
// efficiently with larger delays, as the counter adds parasitic time in each iteration.
|
||||
void delay_us(uint32_t us)
|
||||
{
|
||||
while (us) {
|
||||
if (us < 10) {
|
||||
_delay_us(1);
|
||||
us--;
|
||||
} else if (us < 100) {
|
||||
_delay_us(10);
|
||||
us -= 10;
|
||||
} else if (us < 1000) {
|
||||
_delay_us(100);
|
||||
us -= 100;
|
||||
} else {
|
||||
_delay_ms(1);
|
||||
us -= 1000;
|
||||
void delay_us(uint32_t us) {
|
||||
while (us) {
|
||||
if (us < 10) {
|
||||
_delay_us(1);
|
||||
us--;
|
||||
} else if (us < 100) {
|
||||
_delay_us(10);
|
||||
us -= 10;
|
||||
} else if (us < 1000) {
|
||||
_delay_us(100);
|
||||
us -= 100;
|
||||
} else {
|
||||
_delay_ms(1);
|
||||
us -= 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Simple hypotenuse computation function.
|
||||
float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
|
||||
|
||||
|
||||
float convert_delta_vector_to_unit_vector(float *vector)
|
||||
{
|
||||
uint8_t idx;
|
||||
float magnitude = 0.0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (vector[idx] != 0.0) {
|
||||
magnitude += vector[idx]*vector[idx];
|
||||
}
|
||||
}
|
||||
magnitude = sqrt(magnitude);
|
||||
float inv_magnitude = 1.0/magnitude;
|
||||
for (idx=0; idx<N_AXIS; idx++) { vector[idx] *= inv_magnitude; }
|
||||
return(magnitude);
|
||||
float hypot_f(float x, float y) {
|
||||
return (sqrt(x * x + y * y));
|
||||
}
|
||||
|
||||
|
||||
float limit_value_by_axis_maximum(float *max_value, float *unit_vec)
|
||||
{
|
||||
uint8_t idx;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (unit_vec[idx] != 0) { // Avoid divide by zero.
|
||||
limit_value = min(limit_value,fabs(max_value[idx]/unit_vec[idx]));
|
||||
float convert_delta_vector_to_unit_vector(float *vector) {
|
||||
uint8_t idx;
|
||||
float magnitude = 0.0;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (vector[idx] != 0.0) {
|
||||
magnitude += vector[idx] * vector[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
return(limit_value);
|
||||
magnitude = sqrt(magnitude);
|
||||
float inv_magnitude = 1.0 / magnitude;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
vector[idx] *= inv_magnitude;
|
||||
}
|
||||
return (magnitude);
|
||||
}
|
||||
|
||||
float limit_value_by_axis_maximum(float *max_value, float *unit_vec) {
|
||||
uint8_t idx;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
if (unit_vec[idx] != 0) { // Avoid divide by zero.
|
||||
limit_value = min(limit_value, fabs(max_value[idx] / unit_vec[idx]));
|
||||
}
|
||||
}
|
||||
return (limit_value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
#define nuts_bolts_h
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
#define true 1
|
||||
|
||||
#define SOME_LARGE_VALUE 1.0E+38
|
||||
|
||||
|
|
@ -37,32 +37,32 @@
|
|||
// CoreXY motor assignments. DO NOT ALTER.
|
||||
// NOTE: If the A and B motor axis bindings are changed, this effects the CoreXY equations.
|
||||
#ifdef COREXY
|
||||
#define A_MOTOR X_AXIS // Must be X_AXIS
|
||||
#define B_MOTOR Y_AXIS // Must be Y_AXIS
|
||||
#define A_MOTOR X_AXIS // Must be X_AXIS
|
||||
#define B_MOTOR Y_AXIS // Must be Y_AXIS
|
||||
#endif
|
||||
|
||||
// Conversions
|
||||
#define MM_PER_INCH (25.40)
|
||||
#define INCH_PER_MM (0.0393701)
|
||||
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
|
||||
#define MM_PER_INCH (25.40)
|
||||
#define INCH_PER_MM (0.0393701)
|
||||
#define TICKS_PER_MICROSECOND (F_CPU / 1000000)
|
||||
|
||||
#define DELAY_MODE_DWELL 0
|
||||
#define DELAY_MODE_SYS_SUSPEND 1
|
||||
|
||||
// Useful macros
|
||||
#define clear_vector(a) memset(a, 0, sizeof(a))
|
||||
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*N_AXIS)
|
||||
#define clear_vector(a) memset(a, 0, sizeof(a))
|
||||
#define clear_vector_float(a) memset(a, 0.0, sizeof(float) * N_AXIS)
|
||||
// #define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#define isequal_position_vector(a,b) !(memcmp(a, b, sizeof(float)*N_AXIS))
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define isequal_position_vector(a, b) !(memcmp(a, b, sizeof(float) * N_AXIS))
|
||||
|
||||
// Bit field and masking macros
|
||||
#define bit(n) (1 << n)
|
||||
#define bit_true(x,mask) (x) |= (mask)
|
||||
#define bit_false(x,mask) (x) &= ~(mask)
|
||||
#define bit_istrue(x,mask) ((x & mask) != 0)
|
||||
#define bit_isfalse(x,mask) ((x & mask) == 0)
|
||||
#define bit(n) (1 << n)
|
||||
#define bit_true(x, mask) (x) |= (mask)
|
||||
#define bit_false(x, mask) (x) &= ~(mask)
|
||||
#define bit_istrue(x, mask) ((x & mask) != 0)
|
||||
#define bit_isfalse(x, mask) ((x & mask) == 0)
|
||||
|
||||
// Read a floating point value from a string. Line points to the input buffer, char_counter
|
||||
// is the indexer pointing to the current character of the line, while float_ptr is
|
||||
|
|
|
|||
697
grbl/planner.c
697
grbl/planner.c
|
|
@ -22,42 +22,41 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
static plan_block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions
|
||||
static uint8_t block_buffer_tail; // Index of the block to process now
|
||||
static uint8_t block_buffer_head; // Index of the next block to be pushed
|
||||
static uint8_t next_buffer_head; // Index of the next buffer head
|
||||
static uint8_t block_buffer_planned; // Index of the optimally planned block
|
||||
static plan_block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions
|
||||
static uint8_t block_buffer_tail; // Index of the block to process now
|
||||
static uint8_t block_buffer_head; // Index of the next block to be pushed
|
||||
static uint8_t next_buffer_head; // Index of the next buffer head
|
||||
static uint8_t block_buffer_planned; // Index of the optimally planned block
|
||||
|
||||
// Define planner variables
|
||||
typedef struct {
|
||||
int32_t position[N_AXIS]; // The planner position of the tool in absolute steps. Kept separate
|
||||
int32_t position[N_AXIS]; // The planner position of the tool in absolute steps. Kept separate
|
||||
// from g-code position for movements requiring multiple line motions,
|
||||
// i.e. arcs, canned cycles, and backlash compensation.
|
||||
float previous_unit_vec[N_AXIS]; // Unit vector of previous path line segment
|
||||
float previous_nominal_speed; // Nominal speed of previous path line segment
|
||||
float previous_unit_vec[N_AXIS]; // Unit vector of previous path line segment
|
||||
float previous_nominal_speed; // Nominal speed of previous path line segment
|
||||
} planner_t;
|
||||
|
||||
static planner_t pl;
|
||||
|
||||
|
||||
// Returns the index of the next block in the ring buffer. Also called by stepper segment buffer.
|
||||
uint8_t plan_next_block_index(uint8_t block_index)
|
||||
{
|
||||
block_index++;
|
||||
if (block_index == BLOCK_BUFFER_SIZE) { block_index = 0; }
|
||||
return(block_index);
|
||||
uint8_t plan_next_block_index(uint8_t block_index) {
|
||||
block_index++;
|
||||
if (block_index == BLOCK_BUFFER_SIZE) {
|
||||
block_index = 0;
|
||||
}
|
||||
return (block_index);
|
||||
}
|
||||
|
||||
|
||||
// Returns the index of the previous block in the ring buffer
|
||||
static uint8_t plan_prev_block_index(uint8_t block_index)
|
||||
{
|
||||
if (block_index == 0) { block_index = BLOCK_BUFFER_SIZE; }
|
||||
block_index--;
|
||||
return(block_index);
|
||||
static uint8_t plan_prev_block_index(uint8_t block_index) {
|
||||
if (block_index == 0) {
|
||||
block_index = BLOCK_BUFFER_SIZE;
|
||||
}
|
||||
block_index--;
|
||||
return (block_index);
|
||||
}
|
||||
|
||||
|
||||
/* PLANNER SPEED DEFINITION
|
||||
+--------+ <- current->nominal_speed
|
||||
/ \
|
||||
|
|
@ -123,181 +122,187 @@ static uint8_t plan_prev_block_index(uint8_t block_index)
|
|||
ARM versions should have enough memory and speed for look-ahead blocks numbering up to a hundred or more.
|
||||
|
||||
*/
|
||||
static void planner_recalculate()
|
||||
{
|
||||
// Initialize block index to the last block in the planner buffer.
|
||||
uint8_t block_index = plan_prev_block_index(block_buffer_head);
|
||||
static void planner_recalculate() {
|
||||
// Initialize block index to the last block in the planner buffer.
|
||||
uint8_t block_index = plan_prev_block_index(block_buffer_head);
|
||||
|
||||
// Bail. Can't do anything with one only one plan-able block.
|
||||
if (block_index == block_buffer_planned) { return; }
|
||||
// Bail. Can't do anything with one only one plan-able block.
|
||||
if (block_index == block_buffer_planned) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
|
||||
// block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
|
||||
// NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
|
||||
float entry_speed_sqr;
|
||||
plan_block_t *next;
|
||||
plan_block_t *current = &block_buffer[block_index];
|
||||
// Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
|
||||
// block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
|
||||
// NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
|
||||
float entry_speed_sqr;
|
||||
plan_block_t *next;
|
||||
plan_block_t *current = &block_buffer[block_index];
|
||||
|
||||
// Calculate maximum entry speed for last block in buffer, where the exit speed is always zero.
|
||||
current->entry_speed_sqr = min( current->max_entry_speed_sqr, 2*current->acceleration*current->millimeters);
|
||||
// Calculate maximum entry speed for last block in buffer, where the exit speed is always zero.
|
||||
current->entry_speed_sqr = min(current->max_entry_speed_sqr, 2 * current->acceleration * current->millimeters);
|
||||
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
if (block_index == block_buffer_planned) { // Only two plannable blocks in buffer. Reverse pass complete.
|
||||
// Check if the first block is the tail. If so, notify stepper to update its current parameters.
|
||||
if (block_index == block_buffer_tail) { st_update_plan_block_parameters(); }
|
||||
} else { // Three or more plan-able blocks
|
||||
while (block_index != block_buffer_planned) {
|
||||
next = current;
|
||||
current = &block_buffer[block_index];
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
|
||||
// Check if next block is the tail block(=planned block). If so, update current stepper parameters.
|
||||
if (block_index == block_buffer_tail) { st_update_plan_block_parameters(); }
|
||||
|
||||
// Compute maximum entry speed decelerating over the current block from its exit speed.
|
||||
if (current->entry_speed_sqr != current->max_entry_speed_sqr) {
|
||||
entry_speed_sqr = next->entry_speed_sqr + 2*current->acceleration*current->millimeters;
|
||||
if (entry_speed_sqr < current->max_entry_speed_sqr) {
|
||||
current->entry_speed_sqr = entry_speed_sqr;
|
||||
} else {
|
||||
current->entry_speed_sqr = current->max_entry_speed_sqr;
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
if (block_index == block_buffer_planned) { // Only two plannable blocks in buffer. Reverse pass complete.
|
||||
// Check if the first block is the tail. If so, notify stepper to update its current parameters.
|
||||
if (block_index == block_buffer_tail) {
|
||||
st_update_plan_block_parameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Three or more plan-able blocks
|
||||
while (block_index != block_buffer_planned) {
|
||||
next = current;
|
||||
current = &block_buffer[block_index];
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
|
||||
// Forward Pass: Forward plan the acceleration curve from the planned pointer onward.
|
||||
// Also scans for optimal plan breakpoints and appropriately updates the planned pointer.
|
||||
next = &block_buffer[block_buffer_planned]; // Begin at buffer planned pointer
|
||||
block_index = plan_next_block_index(block_buffer_planned);
|
||||
while (block_index != block_buffer_head) {
|
||||
current = next;
|
||||
next = &block_buffer[block_index];
|
||||
// Check if next block is the tail block(=planned block). If so, update current stepper parameters.
|
||||
if (block_index == block_buffer_tail) {
|
||||
st_update_plan_block_parameters();
|
||||
}
|
||||
|
||||
// Any acceleration detected in the forward pass automatically moves the optimal planned
|
||||
// pointer forward, since everything before this is all optimal. In other words, nothing
|
||||
// can improve the plan from the buffer tail to the planned pointer by logic.
|
||||
if (current->entry_speed_sqr < next->entry_speed_sqr) {
|
||||
entry_speed_sqr = current->entry_speed_sqr + 2*current->acceleration*current->millimeters;
|
||||
// If true, current block is full-acceleration and we can move the planned pointer forward.
|
||||
if (entry_speed_sqr < next->entry_speed_sqr) {
|
||||
next->entry_speed_sqr = entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
|
||||
block_buffer_planned = block_index; // Set optimal plan pointer.
|
||||
}
|
||||
// Compute maximum entry speed decelerating over the current block from its exit speed.
|
||||
if (current->entry_speed_sqr != current->max_entry_speed_sqr) {
|
||||
entry_speed_sqr = next->entry_speed_sqr + 2 * current->acceleration * current->millimeters;
|
||||
if (entry_speed_sqr < current->max_entry_speed_sqr) {
|
||||
current->entry_speed_sqr = entry_speed_sqr;
|
||||
} else {
|
||||
current->entry_speed_sqr = current->max_entry_speed_sqr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any block set at its maximum entry speed also creates an optimal plan up to this
|
||||
// point in the buffer. When the plan is bracketed by either the beginning of the
|
||||
// buffer and a maximum entry speed or two maximum entry speeds, every block in between
|
||||
// cannot logically be further improved. Hence, we don't have to recompute them anymore.
|
||||
if (next->entry_speed_sqr == next->max_entry_speed_sqr) { block_buffer_planned = block_index; }
|
||||
block_index = plan_next_block_index( block_index );
|
||||
}
|
||||
// Forward Pass: Forward plan the acceleration curve from the planned pointer onward.
|
||||
// Also scans for optimal plan breakpoints and appropriately updates the planned pointer.
|
||||
next = &block_buffer[block_buffer_planned]; // Begin at buffer planned pointer
|
||||
block_index = plan_next_block_index(block_buffer_planned);
|
||||
while (block_index != block_buffer_head) {
|
||||
current = next;
|
||||
next = &block_buffer[block_index];
|
||||
|
||||
// Any acceleration detected in the forward pass automatically moves the optimal planned
|
||||
// pointer forward, since everything before this is all optimal. In other words, nothing
|
||||
// can improve the plan from the buffer tail to the planned pointer by logic.
|
||||
if (current->entry_speed_sqr < next->entry_speed_sqr) {
|
||||
entry_speed_sqr = current->entry_speed_sqr + 2 * current->acceleration * current->millimeters;
|
||||
// If true, current block is full-acceleration and we can move the planned pointer forward.
|
||||
if (entry_speed_sqr < next->entry_speed_sqr) {
|
||||
next->entry_speed_sqr = entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
|
||||
block_buffer_planned = block_index; // Set optimal plan pointer.
|
||||
}
|
||||
}
|
||||
|
||||
// Any block set at its maximum entry speed also creates an optimal plan up to this
|
||||
// point in the buffer. When the plan is bracketed by either the beginning of the
|
||||
// buffer and a maximum entry speed or two maximum entry speeds, every block in between
|
||||
// cannot logically be further improved. Hence, we don't have to recompute them anymore.
|
||||
if (next->entry_speed_sqr == next->max_entry_speed_sqr) {
|
||||
block_buffer_planned = block_index;
|
||||
}
|
||||
block_index = plan_next_block_index(block_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void plan_reset()
|
||||
{
|
||||
memset(&pl, 0, sizeof(planner_t)); // Clear planner struct
|
||||
plan_reset_buffer();
|
||||
void plan_reset() {
|
||||
memset(&pl, 0, sizeof(planner_t)); // Clear planner struct
|
||||
plan_reset_buffer();
|
||||
}
|
||||
|
||||
|
||||
void plan_reset_buffer()
|
||||
{
|
||||
block_buffer_tail = 0;
|
||||
block_buffer_head = 0; // Empty = tail
|
||||
next_buffer_head = 1; // plan_next_block_index(block_buffer_head)
|
||||
block_buffer_planned = 0; // = block_buffer_tail;
|
||||
void plan_reset_buffer() {
|
||||
block_buffer_tail = 0;
|
||||
block_buffer_head = 0; // Empty = tail
|
||||
next_buffer_head = 1; // plan_next_block_index(block_buffer_head)
|
||||
block_buffer_planned = 0; // = block_buffer_tail;
|
||||
}
|
||||
|
||||
|
||||
void plan_discard_current_block()
|
||||
{
|
||||
if (block_buffer_head != block_buffer_tail) { // Discard non-empty buffer.
|
||||
uint8_t block_index = plan_next_block_index( block_buffer_tail );
|
||||
// Push block_buffer_planned pointer, if encountered.
|
||||
if (block_buffer_tail == block_buffer_planned) { block_buffer_planned = block_index; }
|
||||
block_buffer_tail = block_index;
|
||||
}
|
||||
void plan_discard_current_block() {
|
||||
if (block_buffer_head != block_buffer_tail) { // Discard non-empty buffer.
|
||||
uint8_t block_index = plan_next_block_index(block_buffer_tail);
|
||||
// Push block_buffer_planned pointer, if encountered.
|
||||
if (block_buffer_tail == block_buffer_planned) {
|
||||
block_buffer_planned = block_index;
|
||||
}
|
||||
block_buffer_tail = block_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns address of planner buffer block used by system motions. Called by segment generator.
|
||||
plan_block_t *plan_get_system_motion_block()
|
||||
{
|
||||
return(&block_buffer[block_buffer_head]);
|
||||
plan_block_t *plan_get_system_motion_block() {
|
||||
return (&block_buffer[block_buffer_head]);
|
||||
}
|
||||
|
||||
|
||||
// Returns address of first planner block, if available. Called by various main program functions.
|
||||
plan_block_t *plan_get_current_block()
|
||||
{
|
||||
if (block_buffer_head == block_buffer_tail) { return(NULL); } // Buffer empty
|
||||
return(&block_buffer[block_buffer_tail]);
|
||||
plan_block_t *plan_get_current_block() {
|
||||
if (block_buffer_head == block_buffer_tail) {
|
||||
return (NULL);
|
||||
} // Buffer empty
|
||||
return (&block_buffer[block_buffer_tail]);
|
||||
}
|
||||
|
||||
|
||||
float plan_get_exec_block_exit_speed_sqr()
|
||||
{
|
||||
uint8_t block_index = plan_next_block_index(block_buffer_tail);
|
||||
if (block_index == block_buffer_head) { return( 0.0 ); }
|
||||
return( block_buffer[block_index].entry_speed_sqr );
|
||||
float plan_get_exec_block_exit_speed_sqr() {
|
||||
uint8_t block_index = plan_next_block_index(block_buffer_tail);
|
||||
if (block_index == block_buffer_head) {
|
||||
return (0.0);
|
||||
}
|
||||
return (block_buffer[block_index].entry_speed_sqr);
|
||||
}
|
||||
|
||||
|
||||
// Returns the availability status of the block ring buffer. True, if full.
|
||||
uint8_t plan_check_full_buffer()
|
||||
{
|
||||
if (block_buffer_tail == next_buffer_head) { return(true); }
|
||||
return(false);
|
||||
uint8_t plan_check_full_buffer() {
|
||||
if (block_buffer_tail == next_buffer_head) {
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
// Computes and returns block nominal speed based on running condition and override values.
|
||||
// NOTE: All system motion commands, such as homing/parking, are not subject to overrides.
|
||||
float plan_compute_profile_nominal_speed(plan_block_t *block)
|
||||
{
|
||||
float nominal_speed = block->programmed_rate;
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01*sys.r_override); }
|
||||
else {
|
||||
if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01*sys.f_override); }
|
||||
if (nominal_speed > block->rapid_rate) { nominal_speed = block->rapid_rate; }
|
||||
}
|
||||
if (nominal_speed > MINIMUM_FEED_RATE) { return(nominal_speed); }
|
||||
return(MINIMUM_FEED_RATE);
|
||||
float plan_compute_profile_nominal_speed(plan_block_t *block) {
|
||||
float nominal_speed = block->programmed_rate;
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) {
|
||||
nominal_speed *= (0.01 * sys.r_override);
|
||||
} else {
|
||||
if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) {
|
||||
nominal_speed *= (0.01 * sys.f_override);
|
||||
}
|
||||
if (nominal_speed > block->rapid_rate) {
|
||||
nominal_speed = block->rapid_rate;
|
||||
}
|
||||
}
|
||||
if (nominal_speed > MINIMUM_FEED_RATE) {
|
||||
return (nominal_speed);
|
||||
}
|
||||
return (MINIMUM_FEED_RATE);
|
||||
}
|
||||
|
||||
|
||||
// Computes and updates the max entry speed (sqr) of the block, based on the minimum of the junction's
|
||||
// previous and current nominal speeds and max junction speed.
|
||||
static void plan_compute_profile_parameters(plan_block_t *block, float nominal_speed, float prev_nominal_speed)
|
||||
{
|
||||
// Compute the junction maximum entry based on the minimum of the junction speed and neighboring nominal speeds.
|
||||
if (nominal_speed > prev_nominal_speed) { block->max_entry_speed_sqr = prev_nominal_speed*prev_nominal_speed; }
|
||||
else { block->max_entry_speed_sqr = nominal_speed*nominal_speed; }
|
||||
if (block->max_entry_speed_sqr > block->max_junction_speed_sqr) { block->max_entry_speed_sqr = block->max_junction_speed_sqr; }
|
||||
static void plan_compute_profile_parameters(plan_block_t *block, float nominal_speed, float prev_nominal_speed) {
|
||||
// Compute the junction maximum entry based on the minimum of the junction speed and neighboring nominal speeds.
|
||||
if (nominal_speed > prev_nominal_speed) {
|
||||
block->max_entry_speed_sqr = prev_nominal_speed * prev_nominal_speed;
|
||||
} else {
|
||||
block->max_entry_speed_sqr = nominal_speed * nominal_speed;
|
||||
}
|
||||
if (block->max_entry_speed_sqr > block->max_junction_speed_sqr) {
|
||||
block->max_entry_speed_sqr = block->max_junction_speed_sqr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Re-calculates buffered motions profile parameters upon a motion-based override change.
|
||||
void plan_update_velocity_profile_parameters()
|
||||
{
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
plan_block_t *block;
|
||||
float nominal_speed;
|
||||
float prev_nominal_speed = SOME_LARGE_VALUE; // Set high for first block nominal speed calculation.
|
||||
while (block_index != block_buffer_head) {
|
||||
block = &block_buffer[block_index];
|
||||
nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, prev_nominal_speed);
|
||||
prev_nominal_speed = nominal_speed;
|
||||
block_index = plan_next_block_index(block_index);
|
||||
}
|
||||
pl.previous_nominal_speed = prev_nominal_speed; // Update prev nominal speed for next incoming block.
|
||||
void plan_update_velocity_profile_parameters() {
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
plan_block_t *block;
|
||||
float nominal_speed;
|
||||
float prev_nominal_speed = SOME_LARGE_VALUE; // Set high for first block nominal speed calculation.
|
||||
while (block_index != block_buffer_head) {
|
||||
block = &block_buffer[block_index];
|
||||
nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, prev_nominal_speed);
|
||||
prev_nominal_speed = nominal_speed;
|
||||
block_index = plan_next_block_index(block_index);
|
||||
}
|
||||
pl.previous_nominal_speed = prev_nominal_speed; // Update prev nominal speed for next incoming block.
|
||||
}
|
||||
|
||||
|
||||
/* Add a new linear movement to the buffer. target[N_AXIS] is the signed, absolute target position
|
||||
in millimeters. Feed rate specifies the speed of the motion. If feed rate is inverted, the feed
|
||||
rate is taken to mean "frequency" and would complete the operation in 1/feed_rate minutes.
|
||||
|
|
@ -312,211 +317,221 @@ void plan_update_velocity_profile_parameters()
|
|||
head. It avoids changing the planner state and preserves the buffer to ensure subsequent gcode
|
||||
motions are still planned correctly, while the stepper module only points to the block buffer head
|
||||
to execute the special system motion. */
|
||||
uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
|
||||
{
|
||||
// Prepare and initialize new block. Copy relevant pl_data for block execution.
|
||||
plan_block_t *block = &block_buffer[block_buffer_head];
|
||||
memset(block,0,sizeof(plan_block_t)); // Zero all block values.
|
||||
block->condition = pl_data->condition;
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data) {
|
||||
// Prepare and initialize new block. Copy relevant pl_data for block execution.
|
||||
plan_block_t *block = &block_buffer[block_buffer_head];
|
||||
memset(block, 0, sizeof(plan_block_t)); // Zero all block values.
|
||||
block->condition = pl_data->condition;
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
block->spindle_speed = pl_data->spindle_speed;
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
block->line_number = pl_data->line_number;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Compute and store initial move distance data.
|
||||
int32_t target_steps[N_AXIS], position_steps[N_AXIS];
|
||||
float unit_vec[N_AXIS], delta_mm;
|
||||
uint8_t idx;
|
||||
// Compute and store initial move distance data.
|
||||
int32_t target_steps[N_AXIS], position_steps[N_AXIS];
|
||||
float unit_vec[N_AXIS], delta_mm;
|
||||
uint8_t idx;
|
||||
|
||||
// Copy position data based on type of motion being planned.
|
||||
if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
|
||||
#ifdef COREXY
|
||||
position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
position_steps[Z_AXIS] = sys_position[Z_AXIS];
|
||||
#else
|
||||
memcpy(position_steps, sys_position, sizeof(sys_position));
|
||||
#endif
|
||||
} else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
|
||||
|
||||
#ifdef COREXY
|
||||
target_steps[A_MOTOR] = lround(target[A_MOTOR]*settings.steps_per_mm[A_MOTOR]);
|
||||
target_steps[B_MOTOR] = lround(target[B_MOTOR]*settings.steps_per_mm[B_MOTOR]);
|
||||
block->steps[A_MOTOR] = labs((target_steps[X_AXIS]-position_steps[X_AXIS]) + (target_steps[Y_AXIS]-position_steps[Y_AXIS]));
|
||||
block->steps[B_MOTOR] = labs((target_steps[X_AXIS]-position_steps[X_AXIS]) - (target_steps[Y_AXIS]-position_steps[Y_AXIS]));
|
||||
#endif
|
||||
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Calculate target position in absolute steps, number of steps for each axis, and determine max step events.
|
||||
// Also, compute individual axes distance for move and prep unit vector calculations.
|
||||
// NOTE: Computes true distance from converted step values.
|
||||
#ifdef COREXY
|
||||
if ( !(idx == A_MOTOR) && !(idx == B_MOTOR) ) {
|
||||
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
|
||||
}
|
||||
block->step_event_count = max(block->step_event_count, block->steps[idx]);
|
||||
if (idx == A_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] + target_steps[Y_AXIS]-position_steps[Y_AXIS])/settings.steps_per_mm[idx];
|
||||
} else if (idx == B_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] - target_steps[Y_AXIS]+position_steps[Y_AXIS])/settings.steps_per_mm[idx];
|
||||
} else {
|
||||
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
|
||||
}
|
||||
#else
|
||||
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
|
||||
block->step_event_count = max(block->step_event_count, block->steps[idx]);
|
||||
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
|
||||
#endif
|
||||
unit_vec[idx] = delta_mm; // Store unit vector numerator
|
||||
|
||||
// Set direction bits. Bit enabled always means direction is negative.
|
||||
if (delta_mm < 0.0 ) { block->direction_bits |= get_direction_pin_mask(idx); }
|
||||
}
|
||||
|
||||
// Bail if this is a zero-length block. Highly unlikely to occur.
|
||||
if (block->step_event_count == 0) { return(PLAN_EMPTY_BLOCK); }
|
||||
|
||||
// Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled
|
||||
// down such that no individual axes maximum values are exceeded with respect to the line direction.
|
||||
// NOTE: This calculation assumes all axes are orthogonal (Cartesian) and works with ABC-axes,
|
||||
// if they are also orthogonal/independent. Operates on the absolute value of the unit vector.
|
||||
block->millimeters = convert_delta_vector_to_unit_vector(unit_vec);
|
||||
block->acceleration = limit_value_by_axis_maximum(settings.acceleration, unit_vec);
|
||||
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);
|
||||
|
||||
// Store programmed rate.
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { block->programmed_rate = block->rapid_rate; }
|
||||
else {
|
||||
block->programmed_rate = pl_data->feed_rate;
|
||||
if (block->condition & PL_COND_FLAG_INVERSE_TIME) { block->programmed_rate *= block->millimeters; }
|
||||
}
|
||||
|
||||
// TODO: Need to check this method handling zero junction speeds when starting from rest.
|
||||
if ((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
|
||||
// Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later.
|
||||
// If system motion, the system motion block always is assumed to start from rest and end at a complete stop.
|
||||
block->entry_speed_sqr = 0.0;
|
||||
block->max_junction_speed_sqr = 0.0; // Starting from rest. Enforce start from zero velocity.
|
||||
|
||||
} else {
|
||||
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
|
||||
// Let a circle be tangent to both previous and current path line segments, where the junction
|
||||
// deviation is defined as the distance from the junction to the closest edge of the circle,
|
||||
// colinear with the circle center. The circular segment joining the two paths represents the
|
||||
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
|
||||
// radius of the circle, defined indirectly by junction deviation. This may be also viewed as
|
||||
// path width or max_jerk in the previous Grbl version. This approach does not actually deviate
|
||||
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
|
||||
// nonlinearities of both the junction angle and junction velocity.
|
||||
//
|
||||
// NOTE: If the junction deviation value is finite, Grbl executes the motions in an exact path
|
||||
// mode (G61). If the junction deviation value is zero, Grbl will execute the motion in an exact
|
||||
// stop mode (G61.1) manner. In the future, if continuous mode (G64) is desired, the math here
|
||||
// is exactly the same. Instead of motioning all the way to junction point, the machine will
|
||||
// just follow the arc circle defined here. The Arduino doesn't have the CPU cycles to perform
|
||||
// a continuous mode path, but ARM-based microcontrollers most certainly do.
|
||||
//
|
||||
// NOTE: The max junction speed is a fixed value, since machine acceleration limits cannot be
|
||||
// changed dynamically during operation nor can the line move geometry. This must be kept in
|
||||
// memory in the event of a feedrate override changing the nominal speeds of blocks, which can
|
||||
// change the overall maximum entry speed conditions of all blocks.
|
||||
|
||||
float junction_unit_vec[N_AXIS];
|
||||
float junction_cos_theta = 0.0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
junction_cos_theta -= pl.previous_unit_vec[idx]*unit_vec[idx];
|
||||
junction_unit_vec[idx] = unit_vec[idx]-pl.previous_unit_vec[idx];
|
||||
}
|
||||
|
||||
// NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
|
||||
if (junction_cos_theta > 0.999999) {
|
||||
// For a 0 degree acute junction, just set minimum junction speed.
|
||||
block->max_junction_speed_sqr = MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED;
|
||||
// Copy position data based on type of motion being planned.
|
||||
if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
|
||||
#ifdef COREXY
|
||||
position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
position_steps[Z_AXIS] = sys_position[Z_AXIS];
|
||||
#else
|
||||
memcpy(position_steps, sys_position, sizeof(sys_position));
|
||||
#endif
|
||||
} else {
|
||||
if (junction_cos_theta < -0.999999) {
|
||||
// Junction is a straight line or 180 degrees. Junction speed is infinite.
|
||||
block->max_junction_speed_sqr = SOME_LARGE_VALUE;
|
||||
} else {
|
||||
convert_delta_vector_to_unit_vector(junction_unit_vec);
|
||||
float junction_acceleration = limit_value_by_axis_maximum(settings.acceleration, junction_unit_vec);
|
||||
float sin_theta_d2 = sqrt(0.5*(1.0-junction_cos_theta)); // Trig half angle identity. Always positive.
|
||||
block->max_junction_speed_sqr = max( MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED,
|
||||
(junction_acceleration * settings.junction_deviation * sin_theta_d2)/(1.0-sin_theta_d2) );
|
||||
}
|
||||
memcpy(position_steps, pl.position, sizeof(pl.position));
|
||||
}
|
||||
}
|
||||
|
||||
// Block system motion from updating this data to ensure next g-code motion is computed correctly.
|
||||
if (!(block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
float nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, pl.previous_nominal_speed);
|
||||
pl.previous_nominal_speed = nominal_speed;
|
||||
|
||||
// Update previous path unit_vector and planner position.
|
||||
memcpy(pl.previous_unit_vec, unit_vec, sizeof(unit_vec)); // pl.previous_unit_vec[] = unit_vec[]
|
||||
memcpy(pl.position, target_steps, sizeof(target_steps)); // pl.position[] = target_steps[]
|
||||
#ifdef COREXY
|
||||
target_steps[A_MOTOR] = lround(target[A_MOTOR] * settings.steps_per_mm[A_MOTOR]);
|
||||
target_steps[B_MOTOR] = lround(target[B_MOTOR] * settings.steps_per_mm[B_MOTOR]);
|
||||
block->steps[A_MOTOR] =
|
||||
labs((target_steps[X_AXIS] - position_steps[X_AXIS]) + (target_steps[Y_AXIS] - position_steps[Y_AXIS]));
|
||||
block->steps[B_MOTOR] =
|
||||
labs((target_steps[X_AXIS] - position_steps[X_AXIS]) - (target_steps[Y_AXIS] - position_steps[Y_AXIS]));
|
||||
#endif
|
||||
|
||||
// New block is all set. Update buffer head and next buffer head indices.
|
||||
block_buffer_head = next_buffer_head;
|
||||
next_buffer_head = plan_next_block_index(block_buffer_head);
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
// Calculate target position in absolute steps, number of steps for each axis, and determine max step events.
|
||||
// Also, compute individual axes distance for move and prep unit vector calculations.
|
||||
// NOTE: Computes true distance from converted step values.
|
||||
#ifdef COREXY
|
||||
if (!(idx == A_MOTOR) && !(idx == B_MOTOR)) {
|
||||
target_steps[idx] = lround(target[idx] * settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx] - position_steps[idx]);
|
||||
}
|
||||
block->step_event_count = max(block->step_event_count, block->steps[idx]);
|
||||
if (idx == A_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS] - position_steps[X_AXIS] + target_steps[Y_AXIS] - position_steps[Y_AXIS]) /
|
||||
settings.steps_per_mm[idx];
|
||||
} else if (idx == B_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS] - position_steps[X_AXIS] - target_steps[Y_AXIS] + position_steps[Y_AXIS]) /
|
||||
settings.steps_per_mm[idx];
|
||||
} else {
|
||||
delta_mm = (target_steps[idx] - position_steps[idx]) / settings.steps_per_mm[idx];
|
||||
}
|
||||
#else
|
||||
target_steps[idx] = lround(target[idx] * settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx] - position_steps[idx]);
|
||||
block->step_event_count = max(block->step_event_count, block->steps[idx]);
|
||||
delta_mm = (target_steps[idx] - position_steps[idx]) / settings.steps_per_mm[idx];
|
||||
#endif
|
||||
unit_vec[idx] = delta_mm; // Store unit vector numerator
|
||||
|
||||
// Finish up by recalculating the plan with the new block.
|
||||
planner_recalculate();
|
||||
}
|
||||
return(PLAN_OK);
|
||||
// Set direction bits. Bit enabled always means direction is negative.
|
||||
if (delta_mm < 0.0) {
|
||||
block->direction_bits |= get_direction_pin_mask(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// Bail if this is a zero-length block. Highly unlikely to occur.
|
||||
if (block->step_event_count == 0) {
|
||||
return (PLAN_EMPTY_BLOCK);
|
||||
}
|
||||
|
||||
// Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled
|
||||
// down such that no individual axes maximum values are exceeded with respect to the line direction.
|
||||
// NOTE: This calculation assumes all axes are orthogonal (Cartesian) and works with ABC-axes,
|
||||
// if they are also orthogonal/independent. Operates on the absolute value of the unit vector.
|
||||
block->millimeters = convert_delta_vector_to_unit_vector(unit_vec);
|
||||
block->acceleration = limit_value_by_axis_maximum(settings.acceleration, unit_vec);
|
||||
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);
|
||||
|
||||
// Store programmed rate.
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) {
|
||||
block->programmed_rate = block->rapid_rate;
|
||||
} else {
|
||||
block->programmed_rate = pl_data->feed_rate;
|
||||
if (block->condition & PL_COND_FLAG_INVERSE_TIME) {
|
||||
block->programmed_rate *= block->millimeters;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Need to check this method handling zero junction speeds when starting from rest.
|
||||
if ((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
|
||||
// Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later.
|
||||
// If system motion, the system motion block always is assumed to start from rest and end at a complete stop.
|
||||
block->entry_speed_sqr = 0.0;
|
||||
block->max_junction_speed_sqr = 0.0; // Starting from rest. Enforce start from zero velocity.
|
||||
|
||||
} else {
|
||||
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
|
||||
// Let a circle be tangent to both previous and current path line segments, where the junction
|
||||
// deviation is defined as the distance from the junction to the closest edge of the circle,
|
||||
// colinear with the circle center. The circular segment joining the two paths represents the
|
||||
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
|
||||
// radius of the circle, defined indirectly by junction deviation. This may be also viewed as
|
||||
// path width or max_jerk in the previous Grbl version. This approach does not actually deviate
|
||||
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
|
||||
// nonlinearities of both the junction angle and junction velocity.
|
||||
//
|
||||
// NOTE: If the junction deviation value is finite, Grbl executes the motions in an exact path
|
||||
// mode (G61). If the junction deviation value is zero, Grbl will execute the motion in an exact
|
||||
// stop mode (G61.1) manner. In the future, if continuous mode (G64) is desired, the math here
|
||||
// is exactly the same. Instead of motioning all the way to junction point, the machine will
|
||||
// just follow the arc circle defined here. The Arduino doesn't have the CPU cycles to perform
|
||||
// a continuous mode path, but ARM-based microcontrollers most certainly do.
|
||||
//
|
||||
// NOTE: The max junction speed is a fixed value, since machine acceleration limits cannot be
|
||||
// changed dynamically during operation nor can the line move geometry. This must be kept in
|
||||
// memory in the event of a feedrate override changing the nominal speeds of blocks, which can
|
||||
// change the overall maximum entry speed conditions of all blocks.
|
||||
|
||||
float junction_unit_vec[N_AXIS];
|
||||
float junction_cos_theta = 0.0;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
junction_cos_theta -= pl.previous_unit_vec[idx] * unit_vec[idx];
|
||||
junction_unit_vec[idx] = unit_vec[idx] - pl.previous_unit_vec[idx];
|
||||
}
|
||||
|
||||
// NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
|
||||
if (junction_cos_theta > 0.999999) {
|
||||
// For a 0 degree acute junction, just set minimum junction speed.
|
||||
block->max_junction_speed_sqr = MINIMUM_JUNCTION_SPEED * MINIMUM_JUNCTION_SPEED;
|
||||
} else {
|
||||
if (junction_cos_theta < -0.999999) {
|
||||
// Junction is a straight line or 180 degrees. Junction speed is infinite.
|
||||
block->max_junction_speed_sqr = SOME_LARGE_VALUE;
|
||||
} else {
|
||||
convert_delta_vector_to_unit_vector(junction_unit_vec);
|
||||
float junction_acceleration = limit_value_by_axis_maximum(settings.acceleration, junction_unit_vec);
|
||||
float sin_theta_d2 =
|
||||
sqrt(0.5 * (1.0 - junction_cos_theta)); // Trig half angle identity. Always positive.
|
||||
block->max_junction_speed_sqr =
|
||||
max(MINIMUM_JUNCTION_SPEED * MINIMUM_JUNCTION_SPEED,
|
||||
(junction_acceleration * settings.junction_deviation * sin_theta_d2) / (1.0 - sin_theta_d2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Block system motion from updating this data to ensure next g-code motion is computed correctly.
|
||||
if (!(block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
float nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, pl.previous_nominal_speed);
|
||||
pl.previous_nominal_speed = nominal_speed;
|
||||
|
||||
// Update previous path unit_vector and planner position.
|
||||
memcpy(pl.previous_unit_vec, unit_vec, sizeof(unit_vec)); // pl.previous_unit_vec[] = unit_vec[]
|
||||
memcpy(pl.position, target_steps, sizeof(target_steps)); // pl.position[] = target_steps[]
|
||||
|
||||
// New block is all set. Update buffer head and next buffer head indices.
|
||||
block_buffer_head = next_buffer_head;
|
||||
next_buffer_head = plan_next_block_index(block_buffer_head);
|
||||
|
||||
// Finish up by recalculating the plan with the new block.
|
||||
planner_recalculate();
|
||||
}
|
||||
return (PLAN_OK);
|
||||
}
|
||||
|
||||
|
||||
// Reset the planner position vectors. Called by the system abort/initialization routine.
|
||||
void plan_sync_position()
|
||||
{
|
||||
// TODO: For motor configurations not in the same coordinate frame as the machine position,
|
||||
// this function needs to be updated to accomodate the difference.
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
pl.position[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
} else if (idx==Y_AXIS) {
|
||||
pl.position[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
} else {
|
||||
void plan_sync_position() {
|
||||
// TODO: For motor configurations not in the same coordinate frame as the machine position,
|
||||
// this function needs to be updated to accomodate the difference.
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
pl.position[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
} else if (idx == Y_AXIS) {
|
||||
pl.position[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
} else {
|
||||
pl.position[idx] = sys_position[idx];
|
||||
}
|
||||
#else
|
||||
pl.position[idx] = sys_position[idx];
|
||||
}
|
||||
#else
|
||||
pl.position[idx] = sys_position[idx];
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of available blocks are in the planner buffer.
|
||||
uint8_t plan_get_block_buffer_available()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return((BLOCK_BUFFER_SIZE-1)-(block_buffer_head-block_buffer_tail)); }
|
||||
return((block_buffer_tail-block_buffer_head-1));
|
||||
uint8_t plan_get_block_buffer_available() {
|
||||
if (block_buffer_head >= block_buffer_tail) {
|
||||
return ((BLOCK_BUFFER_SIZE - 1) - (block_buffer_head - block_buffer_tail));
|
||||
}
|
||||
return ((block_buffer_tail - block_buffer_head - 1));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of active blocks are in the planner buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
|
||||
uint8_t plan_get_block_buffer_count()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return(block_buffer_head-block_buffer_tail); }
|
||||
return(BLOCK_BUFFER_SIZE - (block_buffer_tail-block_buffer_head));
|
||||
uint8_t plan_get_block_buffer_count() {
|
||||
if (block_buffer_head >= block_buffer_tail) {
|
||||
return (block_buffer_head - block_buffer_tail);
|
||||
}
|
||||
return (BLOCK_BUFFER_SIZE - (block_buffer_tail - block_buffer_head));
|
||||
}
|
||||
|
||||
|
||||
// Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail.
|
||||
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.
|
||||
void plan_cycle_reinitialize()
|
||||
{
|
||||
// Re-plan from a complete stop. Reset planner entry speeds and buffer planned pointer.
|
||||
st_update_plan_block_parameters();
|
||||
block_buffer_planned = block_buffer_tail;
|
||||
planner_recalculate();
|
||||
void plan_cycle_reinitialize() {
|
||||
// Re-plan from a complete stop. Reset planner entry speeds and buffer planned pointer.
|
||||
st_update_plan_block_parameters();
|
||||
block_buffer_planned = block_buffer_tail;
|
||||
planner_recalculate();
|
||||
}
|
||||
|
|
|
|||
106
grbl/planner.h
106
grbl/planner.h
|
|
@ -22,83 +22,80 @@
|
|||
#ifndef planner_h
|
||||
#define planner_h
|
||||
|
||||
|
||||
// The number of linear motions that can be in the plan at any give time
|
||||
#ifndef BLOCK_BUFFER_SIZE
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define BLOCK_BUFFER_SIZE 15
|
||||
#else
|
||||
#define BLOCK_BUFFER_SIZE 16
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define BLOCK_BUFFER_SIZE 15
|
||||
#else
|
||||
#define BLOCK_BUFFER_SIZE 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Returned status message from planner.
|
||||
#define PLAN_OK true
|
||||
#define PLAN_OK true
|
||||
#define PLAN_EMPTY_BLOCK false
|
||||
|
||||
// Define planner data condition flags. Used to denote running conditions of a block.
|
||||
#define PL_COND_FLAG_RAPID_MOTION bit(0)
|
||||
#define PL_COND_FLAG_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park.
|
||||
#define PL_COND_FLAG_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override.
|
||||
#define PL_COND_FLAG_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set.
|
||||
#define PL_COND_FLAG_SPINDLE_CW bit(4)
|
||||
#define PL_COND_FLAG_SPINDLE_CCW bit(5)
|
||||
#define PL_COND_FLAG_COOLANT_FLOOD bit(6)
|
||||
#define PL_COND_FLAG_COOLANT_MIST bit(7)
|
||||
#define PL_COND_MOTION_MASK (PL_COND_FLAG_RAPID_MOTION|PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE)
|
||||
#define PL_COND_SPINDLE_MASK (PL_COND_FLAG_SPINDLE_CW|PL_COND_FLAG_SPINDLE_CCW)
|
||||
#define PL_COND_ACCESSORY_MASK (PL_COND_FLAG_SPINDLE_CW|PL_COND_FLAG_SPINDLE_CCW|PL_COND_FLAG_COOLANT_FLOOD|PL_COND_FLAG_COOLANT_MIST)
|
||||
|
||||
#define PL_COND_FLAG_RAPID_MOTION bit(0)
|
||||
#define PL_COND_FLAG_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park.
|
||||
#define PL_COND_FLAG_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override.
|
||||
#define PL_COND_FLAG_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set.
|
||||
#define PL_COND_FLAG_SPINDLE_CW bit(4)
|
||||
#define PL_COND_FLAG_SPINDLE_CCW bit(5)
|
||||
#define PL_COND_FLAG_COOLANT_FLOOD bit(6)
|
||||
#define PL_COND_FLAG_COOLANT_MIST bit(7)
|
||||
#define PL_COND_MOTION_MASK (PL_COND_FLAG_RAPID_MOTION | PL_COND_FLAG_SYSTEM_MOTION | PL_COND_FLAG_NO_FEED_OVERRIDE)
|
||||
#define PL_COND_SPINDLE_MASK (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)
|
||||
#define PL_COND_ACCESSORY_MASK \
|
||||
(PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW | PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_MIST)
|
||||
|
||||
// This struct stores a linear movement of a g-code block motion with its critical "nominal" values
|
||||
// are as specified in the source g-code.
|
||||
typedef struct {
|
||||
// Fields used by the bresenham algorithm for tracing the line
|
||||
// NOTE: Used by stepper algorithm to execute the block correctly. Do not alter these values.
|
||||
uint32_t steps[N_AXIS]; // Step count along each axis
|
||||
uint32_t step_event_count; // The maximum step axis count and number of steps required to complete this block.
|
||||
uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
|
||||
// Fields used by the bresenham algorithm for tracing the line
|
||||
// NOTE: Used by stepper algorithm to execute the block correctly. Do not alter these values.
|
||||
uint32_t steps[N_AXIS]; // Step count along each axis
|
||||
uint32_t step_event_count; // The maximum step axis count and number of steps required to complete this block.
|
||||
uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
|
||||
|
||||
// Block condition data to ensure correct execution depending on states and overrides.
|
||||
uint8_t condition; // Block bitflag variable defining block run conditions. Copied from pl_line_data.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Block line number for real-time reporting. Copied from pl_line_data.
|
||||
#endif
|
||||
// Block condition data to ensure correct execution depending on states and overrides.
|
||||
uint8_t condition; // Block bitflag variable defining block run conditions. Copied from pl_line_data.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Block line number for real-time reporting. Copied from pl_line_data.
|
||||
#endif
|
||||
|
||||
// Fields used by the motion planner to manage acceleration. Some of these values may be updated
|
||||
// by the stepper module during execution of special motion cases for replanning purposes.
|
||||
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
|
||||
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
|
||||
// neighboring nominal speeds with overrides in (mm/min)^2
|
||||
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
|
||||
float millimeters; // The remaining distance for this block to be executed in (mm).
|
||||
// NOTE: This value may be altered by stepper algorithm during execution.
|
||||
// Fields used by the motion planner to manage acceleration. Some of these values may be updated
|
||||
// by the stepper module during execution of special motion cases for replanning purposes.
|
||||
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
|
||||
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
|
||||
// neighboring nominal speeds with overrides in (mm/min)^2
|
||||
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
|
||||
float millimeters; // The remaining distance for this block to be executed in (mm).
|
||||
// NOTE: This value may be altered by stepper algorithm during execution.
|
||||
|
||||
// Stored rate limiting data used by planner when changes occur.
|
||||
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
|
||||
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
|
||||
float programmed_rate; // Programmed rate of this block (mm/min).
|
||||
// Stored rate limiting data used by planner when changes occur.
|
||||
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
|
||||
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
|
||||
float programmed_rate; // Programmed rate of this block (mm/min).
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// Stored spindle speed data used by spindle overrides and resuming methods.
|
||||
float spindle_speed; // Block spindle speed. Copied from pl_line_data.
|
||||
#endif
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// Stored spindle speed data used by spindle overrides and resuming methods.
|
||||
float spindle_speed; // Block spindle speed. Copied from pl_line_data.
|
||||
#endif
|
||||
} plan_block_t;
|
||||
|
||||
|
||||
// Planner data prototype. Must be used when passing new motions to the planner.
|
||||
typedef struct {
|
||||
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
|
||||
float spindle_speed; // Desired spindle speed through line motion.
|
||||
uint8_t condition; // Bitflag variable to indicate planner conditions. See defines above.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Desired line number to report when executing.
|
||||
#endif
|
||||
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
|
||||
float spindle_speed; // Desired spindle speed through line motion.
|
||||
uint8_t condition; // Bitflag variable to indicate planner conditions. See defines above.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Desired line number to report when executing.
|
||||
#endif
|
||||
} plan_line_data_t;
|
||||
|
||||
|
||||
// Initialize and reset the motion plan subsystem
|
||||
void plan_reset(); // Reset all
|
||||
void plan_reset(); // Reset all
|
||||
void plan_reset_buffer(); // Reset buffer only.
|
||||
|
||||
// Add a new linear movement to the buffer. target[N_AXIS] is the signed, absolute target position
|
||||
|
|
@ -146,5 +143,4 @@ uint8_t plan_check_full_buffer();
|
|||
|
||||
void plan_get_planner_mpos(float *target);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
199
grbl/print.c
199
grbl/print.c
|
|
@ -21,23 +21,16 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
void printString(const char *s)
|
||||
{
|
||||
while (*s)
|
||||
serial_write(*s++);
|
||||
void printString(const char *s) {
|
||||
while (*s) serial_write(*s++);
|
||||
}
|
||||
|
||||
|
||||
// Print a string stored in PGM-memory
|
||||
void printPgmString(const char *s)
|
||||
{
|
||||
char c;
|
||||
while ((c = pgm_read_byte_near(s++)))
|
||||
serial_write(c);
|
||||
void printPgmString(const char *s) {
|
||||
char c;
|
||||
while ((c = pgm_read_byte_near(s++))) serial_write(c);
|
||||
}
|
||||
|
||||
|
||||
// void printIntegerInBase(unsigned long n, unsigned long base)
|
||||
// {
|
||||
// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
|
|
@ -59,133 +52,129 @@ void printPgmString(const char *s)
|
|||
// 'A' + buf[i - 1] - 10);
|
||||
// }
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 10.
|
||||
void print_uint8_base10(uint8_t n)
|
||||
{
|
||||
uint8_t digit_a = 0;
|
||||
uint8_t digit_b = 0;
|
||||
if (n >= 100) { // 100-255
|
||||
digit_a = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
if (n >= 10) { // 10-99
|
||||
digit_b = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
serial_write('0' + n);
|
||||
if (digit_b) { serial_write(digit_b); }
|
||||
if (digit_a) { serial_write(digit_a); }
|
||||
void print_uint8_base10(uint8_t n) {
|
||||
uint8_t digit_a = 0;
|
||||
uint8_t digit_b = 0;
|
||||
if (n >= 100) { // 100-255
|
||||
digit_a = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
if (n >= 10) { // 10-99
|
||||
digit_b = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
serial_write('0' + n);
|
||||
if (digit_b) {
|
||||
serial_write(digit_b);
|
||||
}
|
||||
if (digit_a) {
|
||||
serial_write(digit_a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 2 with desired number of desired digits.
|
||||
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits) {
|
||||
unsigned char buf[digits];
|
||||
uint8_t i = 0;
|
||||
unsigned char buf[digits];
|
||||
uint8_t i = 0;
|
||||
|
||||
for (; i < digits; i++) {
|
||||
buf[i] = n % 2 ;
|
||||
n /= 2;
|
||||
}
|
||||
for (; i < digits; i++) {
|
||||
buf[i] = n % 2;
|
||||
n /= 2;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
serial_write('0' + buf[i - 1]);
|
||||
for (; i > 0; i--) serial_write('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
void print_uint32_base10(uint32_t n) {
|
||||
if (n == 0) {
|
||||
serial_write('0');
|
||||
return;
|
||||
}
|
||||
|
||||
void print_uint32_base10(uint32_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
serial_write('0');
|
||||
return;
|
||||
}
|
||||
unsigned char buf[10];
|
||||
uint8_t i = 0;
|
||||
|
||||
unsigned char buf[10];
|
||||
uint8_t i = 0;
|
||||
while (n > 0) {
|
||||
buf[i++] = n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
buf[i++] = n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
serial_write('0' + buf[i-1]);
|
||||
for (; i > 0; i--) serial_write('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void printInteger(long n)
|
||||
{
|
||||
if (n < 0) {
|
||||
serial_write('-');
|
||||
print_uint32_base10(-n);
|
||||
} else {
|
||||
print_uint32_base10(n);
|
||||
}
|
||||
void printInteger(long n) {
|
||||
if (n < 0) {
|
||||
serial_write('-');
|
||||
print_uint32_base10(-n);
|
||||
} else {
|
||||
print_uint32_base10(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert float to string by immediately converting to a long integer, which contains
|
||||
// more digits than a float. Number of decimal places, which are tracked by a counter,
|
||||
// may be set by the user. The integer is then efficiently converted to a string.
|
||||
// NOTE: AVR '%' and '/' integer operations are very efficient. Bitshifting speed-up
|
||||
// techniques are actually just slightly slower. Found this out the hard way.
|
||||
void printFloat(float n, uint8_t decimal_places)
|
||||
{
|
||||
if (n < 0) {
|
||||
serial_write('-');
|
||||
n = -n;
|
||||
}
|
||||
void printFloat(float n, uint8_t decimal_places) {
|
||||
if (n < 0) {
|
||||
serial_write('-');
|
||||
n = -n;
|
||||
}
|
||||
|
||||
uint8_t decimals = decimal_places;
|
||||
while (decimals >= 2) { // Quickly convert values expected to be E0 to E-4.
|
||||
n *= 100;
|
||||
decimals -= 2;
|
||||
}
|
||||
if (decimals) { n *= 10; }
|
||||
n += 0.5; // Add rounding factor. Ensures carryover through entire value.
|
||||
uint8_t decimals = decimal_places;
|
||||
while (decimals >= 2) { // Quickly convert values expected to be E0 to E-4.
|
||||
n *= 100;
|
||||
decimals -= 2;
|
||||
}
|
||||
if (decimals) {
|
||||
n *= 10;
|
||||
}
|
||||
n += 0.5; // Add rounding factor. Ensures carryover through entire value.
|
||||
|
||||
// Generate digits backwards and store in string.
|
||||
unsigned char buf[13];
|
||||
uint8_t i = 0;
|
||||
uint32_t a = (long)n;
|
||||
while(a > 0) {
|
||||
buf[i++] = (a % 10) + '0'; // Get digit
|
||||
a /= 10;
|
||||
}
|
||||
while (i < decimal_places) {
|
||||
buf[i++] = '0'; // Fill in zeros to decimal point for (n < 1)
|
||||
}
|
||||
if (i == decimal_places) { // Fill in leading zero, if needed.
|
||||
buf[i++] = '0';
|
||||
}
|
||||
// Generate digits backwards and store in string.
|
||||
unsigned char buf[13];
|
||||
uint8_t i = 0;
|
||||
uint32_t a = (long)n;
|
||||
while (a > 0) {
|
||||
buf[i++] = (a % 10) + '0'; // Get digit
|
||||
a /= 10;
|
||||
}
|
||||
while (i < decimal_places) {
|
||||
buf[i++] = '0'; // Fill in zeros to decimal point for (n < 1)
|
||||
}
|
||||
if (i == decimal_places) { // Fill in leading zero, if needed.
|
||||
buf[i++] = '0';
|
||||
}
|
||||
|
||||
// Print the generated string.
|
||||
for (; i > 0; i--) {
|
||||
if (i == decimal_places) { serial_write('.'); } // Insert decimal point in right place.
|
||||
serial_write(buf[i-1]);
|
||||
}
|
||||
// Print the generated string.
|
||||
for (; i > 0; i--) {
|
||||
if (i == decimal_places) {
|
||||
serial_write('.');
|
||||
} // Insert decimal point in right place.
|
||||
serial_write(buf[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Floating value printing handlers for special variables types used in Grbl and are defined
|
||||
// in the config.h.
|
||||
// - CoordValue: Handles all position or coordinate values in inches or mm reporting.
|
||||
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
|
||||
void printFloat_CoordValue(float n) {
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
printFloat(n*INCH_PER_MM,N_DECIMAL_COORDVALUE_INCH);
|
||||
} else {
|
||||
printFloat(n,N_DECIMAL_COORDVALUE_MM);
|
||||
}
|
||||
if (bit_istrue(settings.flags, BITFLAG_REPORT_INCHES)) {
|
||||
printFloat(n * INCH_PER_MM, N_DECIMAL_COORDVALUE_INCH);
|
||||
} else {
|
||||
printFloat(n, N_DECIMAL_COORDVALUE_MM);
|
||||
}
|
||||
}
|
||||
|
||||
void printFloat_RateValue(float n) {
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
printFloat(n*INCH_PER_MM,N_DECIMAL_RATEVALUE_INCH);
|
||||
} else {
|
||||
printFloat(n,N_DECIMAL_RATEVALUE_MM);
|
||||
}
|
||||
if (bit_istrue(settings.flags, BITFLAG_REPORT_INCHES)) {
|
||||
printFloat(n * INCH_PER_MM, N_DECIMAL_RATEVALUE_INCH);
|
||||
} else {
|
||||
printFloat(n, N_DECIMAL_RATEVALUE_MM);
|
||||
}
|
||||
}
|
||||
|
||||
// Debug tool to print free memory in bytes at the called point.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
#ifndef print_h
|
||||
#define print_h
|
||||
|
||||
|
||||
void printString(const char *s);
|
||||
|
||||
void printPgmString(const char *s);
|
||||
|
|
|
|||
50
grbl/probe.c
50
grbl/probe.c
|
|
@ -20,47 +20,45 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Inverts the probe pin state depending on user settings and probing cycle mode.
|
||||
uint8_t probe_invert_mask;
|
||||
|
||||
|
||||
// Probe pin initialization routine.
|
||||
void probe_init()
|
||||
{
|
||||
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
|
||||
#ifdef DISABLE_PROBE_PIN_PULL_UP
|
||||
void probe_init() {
|
||||
PROBE_DDR &= ~(PROBE_MASK); // Configure as input pins
|
||||
#ifdef DISABLE_PROBE_PIN_PULL_UP
|
||||
PROBE_PORT &= ~(PROBE_MASK); // Normal low operation. Requires external pull-down.
|
||||
#else
|
||||
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
probe_configure_invert_mask(false); // Initialize invert mask.
|
||||
#else
|
||||
PROBE_PORT |= PROBE_MASK; // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
probe_configure_invert_mask(false); // Initialize invert mask.
|
||||
}
|
||||
|
||||
|
||||
// Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to
|
||||
// appropriately set the pin logic according to setting for normal-high/normal-low operation
|
||||
// and the probing cycle modes for toward-workpiece/away-from-workpiece.
|
||||
void probe_configure_invert_mask(uint8_t is_probe_away)
|
||||
{
|
||||
probe_invert_mask = 0; // Initialize as zero.
|
||||
if (bit_isfalse(settings.flags,BITFLAG_INVERT_PROBE_PIN)) { probe_invert_mask ^= PROBE_MASK; }
|
||||
if (is_probe_away) { probe_invert_mask ^= PROBE_MASK; }
|
||||
void probe_configure_invert_mask(uint8_t is_probe_away) {
|
||||
probe_invert_mask = 0; // Initialize as zero.
|
||||
if (bit_isfalse(settings.flags, BITFLAG_INVERT_PROBE_PIN)) {
|
||||
probe_invert_mask ^= PROBE_MASK;
|
||||
}
|
||||
if (is_probe_away) {
|
||||
probe_invert_mask ^= PROBE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
|
||||
uint8_t probe_get_state() { return((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask); }
|
||||
|
||||
uint8_t probe_get_state() {
|
||||
return ((PROBE_PIN & PROBE_MASK) ^ probe_invert_mask);
|
||||
}
|
||||
|
||||
// Monitors probe pin state and records the system position when detected. Called by the
|
||||
// stepper ISR per ISR tick.
|
||||
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
|
||||
void probe_state_monitor()
|
||||
{
|
||||
if (probe_get_state()) {
|
||||
sys_probe_state = PROBE_OFF;
|
||||
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
bit_true(sys_rt_exec_state, EXEC_MOTION_CANCEL);
|
||||
}
|
||||
void probe_state_monitor() {
|
||||
if (probe_get_state()) {
|
||||
sys_probe_state = PROBE_OFF;
|
||||
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
bit_true(sys_rt_exec_state, EXEC_MOTION_CANCEL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
#define probe_h
|
||||
|
||||
// Values that define the probing state machine.
|
||||
#define PROBE_OFF 0 // Probing disabled or not in use. (Must be zero.)
|
||||
#define PROBE_ACTIVE 1 // Actively watching the input pin.
|
||||
#define PROBE_OFF 0 // Probing disabled or not in use. (Must be zero.)
|
||||
#define PROBE_ACTIVE 1 // Actively watching the input pin.
|
||||
|
||||
// Probe pin initialization routine.
|
||||
void probe_init();
|
||||
|
|
|
|||
1372
grbl/protocol.c
1372
grbl/protocol.c
File diff suppressed because it is too large
Load diff
|
|
@ -29,7 +29,7 @@
|
|||
// memory space we can invest into here or we re-write the g-code parser not to have this
|
||||
// buffer.
|
||||
#ifndef LINE_BUFFER_SIZE
|
||||
#define LINE_BUFFER_SIZE 80
|
||||
#define LINE_BUFFER_SIZE 80
|
||||
#endif
|
||||
|
||||
// Starts Grbl main loop. It handles all incoming characters from the serial port and executes
|
||||
|
|
|
|||
963
grbl/report.c
963
grbl/report.c
File diff suppressed because it is too large
Load diff
108
grbl/report.h
108
grbl/report.h
|
|
@ -21,68 +21,68 @@
|
|||
#define report_h
|
||||
|
||||
// Define Grbl status codes. Valid values (0-255)
|
||||
#define STATUS_OK 0
|
||||
#define STATUS_OK 0
|
||||
#define STATUS_EXPECTED_COMMAND_LETTER 1
|
||||
#define STATUS_BAD_NUMBER_FORMAT 2
|
||||
#define STATUS_INVALID_STATEMENT 3
|
||||
#define STATUS_NEGATIVE_VALUE 4
|
||||
#define STATUS_SETTING_DISABLED 5
|
||||
#define STATUS_SETTING_STEP_PULSE_MIN 6
|
||||
#define STATUS_SETTING_READ_FAIL 7
|
||||
#define STATUS_IDLE_ERROR 8
|
||||
#define STATUS_SYSTEM_GC_LOCK 9
|
||||
#define STATUS_SOFT_LIMIT_ERROR 10
|
||||
#define STATUS_OVERFLOW 11
|
||||
#define STATUS_MAX_STEP_RATE_EXCEEDED 12
|
||||
#define STATUS_CHECK_DOOR 13
|
||||
#define STATUS_LINE_LENGTH_EXCEEDED 14
|
||||
#define STATUS_TRAVEL_EXCEEDED 15
|
||||
#define STATUS_INVALID_JOG_COMMAND 16
|
||||
#define STATUS_SETTING_DISABLED_LASER 17
|
||||
#define STATUS_BAD_NUMBER_FORMAT 2
|
||||
#define STATUS_INVALID_STATEMENT 3
|
||||
#define STATUS_NEGATIVE_VALUE 4
|
||||
#define STATUS_SETTING_DISABLED 5
|
||||
#define STATUS_SETTING_STEP_PULSE_MIN 6
|
||||
#define STATUS_SETTING_READ_FAIL 7
|
||||
#define STATUS_IDLE_ERROR 8
|
||||
#define STATUS_SYSTEM_GC_LOCK 9
|
||||
#define STATUS_SOFT_LIMIT_ERROR 10
|
||||
#define STATUS_OVERFLOW 11
|
||||
#define STATUS_MAX_STEP_RATE_EXCEEDED 12
|
||||
#define STATUS_CHECK_DOOR 13
|
||||
#define STATUS_LINE_LENGTH_EXCEEDED 14
|
||||
#define STATUS_TRAVEL_EXCEEDED 15
|
||||
#define STATUS_INVALID_JOG_COMMAND 16
|
||||
#define STATUS_SETTING_DISABLED_LASER 17
|
||||
|
||||
#define STATUS_GCODE_UNSUPPORTED_COMMAND 20
|
||||
#define STATUS_GCODE_MODAL_GROUP_VIOLATION 21
|
||||
#define STATUS_GCODE_UNDEFINED_FEED_RATE 22
|
||||
#define STATUS_GCODE_UNSUPPORTED_COMMAND 20
|
||||
#define STATUS_GCODE_MODAL_GROUP_VIOLATION 21
|
||||
#define STATUS_GCODE_UNDEFINED_FEED_RATE 22
|
||||
#define STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER 23
|
||||
#define STATUS_GCODE_AXIS_COMMAND_CONFLICT 24
|
||||
#define STATUS_GCODE_WORD_REPEATED 25
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS 26
|
||||
#define STATUS_GCODE_INVALID_LINE_NUMBER 27
|
||||
#define STATUS_GCODE_VALUE_WORD_MISSING 28
|
||||
#define STATUS_GCODE_UNSUPPORTED_COORD_SYS 29
|
||||
#define STATUS_GCODE_G53_INVALID_MOTION_MODE 30
|
||||
#define STATUS_GCODE_AXIS_WORDS_EXIST 31
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE 32
|
||||
#define STATUS_GCODE_INVALID_TARGET 33
|
||||
#define STATUS_GCODE_ARC_RADIUS_ERROR 34
|
||||
#define STATUS_GCODE_NO_OFFSETS_IN_PLANE 35
|
||||
#define STATUS_GCODE_UNUSED_WORDS 36
|
||||
#define STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR 37
|
||||
#define STATUS_GCODE_MAX_VALUE_EXCEEDED 38
|
||||
#define STATUS_GCODE_AXIS_COMMAND_CONFLICT 24
|
||||
#define STATUS_GCODE_WORD_REPEATED 25
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS 26
|
||||
#define STATUS_GCODE_INVALID_LINE_NUMBER 27
|
||||
#define STATUS_GCODE_VALUE_WORD_MISSING 28
|
||||
#define STATUS_GCODE_UNSUPPORTED_COORD_SYS 29
|
||||
#define STATUS_GCODE_G53_INVALID_MOTION_MODE 30
|
||||
#define STATUS_GCODE_AXIS_WORDS_EXIST 31
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE 32
|
||||
#define STATUS_GCODE_INVALID_TARGET 33
|
||||
#define STATUS_GCODE_ARC_RADIUS_ERROR 34
|
||||
#define STATUS_GCODE_NO_OFFSETS_IN_PLANE 35
|
||||
#define STATUS_GCODE_UNUSED_WORDS 36
|
||||
#define STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR 37
|
||||
#define STATUS_GCODE_MAX_VALUE_EXCEEDED 38
|
||||
|
||||
// Define Grbl alarm codes. Valid values (1-255). 0 is reserved.
|
||||
#define ALARM_HARD_LIMIT_ERROR EXEC_ALARM_HARD_LIMIT
|
||||
#define ALARM_SOFT_LIMIT_ERROR EXEC_ALARM_SOFT_LIMIT
|
||||
#define ALARM_ABORT_CYCLE EXEC_ALARM_ABORT_CYCLE
|
||||
#define ALARM_PROBE_FAIL_INITIAL EXEC_ALARM_PROBE_FAIL_INITIAL
|
||||
#define ALARM_PROBE_FAIL_CONTACT EXEC_ALARM_PROBE_FAIL_CONTACT
|
||||
#define ALARM_HOMING_FAIL_RESET EXEC_ALARM_HOMING_FAIL_RESET
|
||||
#define ALARM_HOMING_FAIL_DOOR EXEC_ALARM_HOMING_FAIL_DOOR
|
||||
#define ALARM_HOMING_FAIL_PULLOFF EXEC_ALARM_HOMING_FAIL_PULLOFF
|
||||
#define ALARM_HOMING_FAIL_APPROACH EXEC_ALARM_HOMING_FAIL_APPROACH
|
||||
#define ALARM_HARD_LIMIT_ERROR EXEC_ALARM_HARD_LIMIT
|
||||
#define ALARM_SOFT_LIMIT_ERROR EXEC_ALARM_SOFT_LIMIT
|
||||
#define ALARM_ABORT_CYCLE EXEC_ALARM_ABORT_CYCLE
|
||||
#define ALARM_PROBE_FAIL_INITIAL EXEC_ALARM_PROBE_FAIL_INITIAL
|
||||
#define ALARM_PROBE_FAIL_CONTACT EXEC_ALARM_PROBE_FAIL_CONTACT
|
||||
#define ALARM_HOMING_FAIL_RESET EXEC_ALARM_HOMING_FAIL_RESET
|
||||
#define ALARM_HOMING_FAIL_DOOR EXEC_ALARM_HOMING_FAIL_DOOR
|
||||
#define ALARM_HOMING_FAIL_PULLOFF EXEC_ALARM_HOMING_FAIL_PULLOFF
|
||||
#define ALARM_HOMING_FAIL_APPROACH EXEC_ALARM_HOMING_FAIL_APPROACH
|
||||
|
||||
// Define Grbl feedback message codes. Valid values (0-255).
|
||||
#define MESSAGE_CRITICAL_EVENT 1
|
||||
#define MESSAGE_ALARM_LOCK 2
|
||||
#define MESSAGE_ALARM_UNLOCK 3
|
||||
#define MESSAGE_ENABLED 4
|
||||
#define MESSAGE_DISABLED 5
|
||||
#define MESSAGE_CRITICAL_EVENT 1
|
||||
#define MESSAGE_ALARM_LOCK 2
|
||||
#define MESSAGE_ALARM_UNLOCK 3
|
||||
#define MESSAGE_ENABLED 4
|
||||
#define MESSAGE_DISABLED 5
|
||||
#define MESSAGE_SAFETY_DOOR_AJAR 6
|
||||
#define MESSAGE_CHECK_LIMITS 7
|
||||
#define MESSAGE_PROGRAM_END 8
|
||||
#define MESSAGE_CHECK_LIMITS 7
|
||||
#define MESSAGE_PROGRAM_END 8
|
||||
#define MESSAGE_RESTORE_DEFAULTS 9
|
||||
#define MESSAGE_SPINDLE_RESTORE 10
|
||||
#define MESSAGE_SLEEP_MODE 11
|
||||
#define MESSAGE_SPINDLE_RESTORE 10
|
||||
#define MESSAGE_SLEEP_MODE 11
|
||||
|
||||
// Prints system status messages.
|
||||
void report_status_message(uint8_t status_code);
|
||||
|
|
@ -125,7 +125,7 @@ void report_execute_startup_message(char *line, uint8_t status_code);
|
|||
void report_build_info(char *line);
|
||||
|
||||
#ifdef DEBUG
|
||||
void report_realtime_debug();
|
||||
void report_realtime_debug();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
282
grbl/serial.c
282
grbl/serial.c
|
|
@ -21,184 +21,200 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
#define RX_RING_BUFFER (RX_BUFFER_SIZE+1)
|
||||
#define TX_RING_BUFFER (TX_BUFFER_SIZE+1)
|
||||
#define RX_RING_BUFFER (RX_BUFFER_SIZE + 1)
|
||||
#define TX_RING_BUFFER (TX_BUFFER_SIZE + 1)
|
||||
|
||||
uint8_t serial_rx_buffer[RX_RING_BUFFER];
|
||||
uint8_t serial_rx_buffer_head = 0;
|
||||
uint8_t serial_rx_buffer[RX_RING_BUFFER];
|
||||
uint8_t serial_rx_buffer_head = 0;
|
||||
volatile uint8_t serial_rx_buffer_tail = 0;
|
||||
|
||||
uint8_t serial_tx_buffer[TX_RING_BUFFER];
|
||||
uint8_t serial_tx_buffer_head = 0;
|
||||
uint8_t serial_tx_buffer[TX_RING_BUFFER];
|
||||
uint8_t serial_tx_buffer_head = 0;
|
||||
volatile uint8_t serial_tx_buffer_tail = 0;
|
||||
|
||||
|
||||
// Returns the number of bytes available in the RX serial buffer.
|
||||
uint8_t serial_get_rx_buffer_available()
|
||||
{
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head >= rtail) { return(RX_BUFFER_SIZE - (serial_rx_buffer_head-rtail)); }
|
||||
return((rtail-serial_rx_buffer_head-1));
|
||||
uint8_t serial_get_rx_buffer_available() {
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head >= rtail) {
|
||||
return (RX_BUFFER_SIZE - (serial_rx_buffer_head - rtail));
|
||||
}
|
||||
return ((rtail - serial_rx_buffer_head - 1));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of bytes used in the RX serial buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h.
|
||||
uint8_t serial_get_rx_buffer_count()
|
||||
{
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head >= rtail) { return(serial_rx_buffer_head-rtail); }
|
||||
return (RX_BUFFER_SIZE - (rtail-serial_rx_buffer_head));
|
||||
uint8_t serial_get_rx_buffer_count() {
|
||||
uint8_t rtail = serial_rx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head >= rtail) {
|
||||
return (serial_rx_buffer_head - rtail);
|
||||
}
|
||||
return (RX_BUFFER_SIZE - (rtail - serial_rx_buffer_head));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of bytes used in the TX serial buffer.
|
||||
// NOTE: Not used except for debugging and ensuring no TX bottlenecks.
|
||||
uint8_t serial_get_tx_buffer_count()
|
||||
{
|
||||
uint8_t ttail = serial_tx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_tx_buffer_head >= ttail) { return(serial_tx_buffer_head-ttail); }
|
||||
return (TX_RING_BUFFER - (ttail-serial_tx_buffer_head));
|
||||
uint8_t serial_get_tx_buffer_count() {
|
||||
uint8_t ttail = serial_tx_buffer_tail; // Copy to limit multiple calls to volatile
|
||||
if (serial_tx_buffer_head >= ttail) {
|
||||
return (serial_tx_buffer_head - ttail);
|
||||
}
|
||||
return (TX_RING_BUFFER - (ttail - serial_tx_buffer_head));
|
||||
}
|
||||
|
||||
|
||||
void serial_init()
|
||||
{
|
||||
// Set baud rate
|
||||
#if BAUD_RATE < 57600
|
||||
uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1)/2 ;
|
||||
void serial_init() {
|
||||
// Set baud rate
|
||||
#if BAUD_RATE < 57600
|
||||
uint16_t UBRR0_value = ((F_CPU / (8L * BAUD_RATE)) - 1) / 2;
|
||||
UCSR0A &= ~(1 << U2X0); // baud doubler off - Only needed on Uno XXX
|
||||
#else
|
||||
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1)/2;
|
||||
UCSR0A |= (1 << U2X0); // baud doubler on for high baud rates, i.e. 115200
|
||||
#endif
|
||||
UBRR0H = UBRR0_value >> 8;
|
||||
UBRR0L = UBRR0_value;
|
||||
#else
|
||||
uint16_t UBRR0_value = ((F_CPU / (4L * BAUD_RATE)) - 1) / 2;
|
||||
UCSR0A |= (1 << U2X0); // baud doubler on for high baud rates, i.e. 115200
|
||||
#endif
|
||||
UBRR0H = UBRR0_value >> 8;
|
||||
UBRR0L = UBRR0_value;
|
||||
|
||||
// enable rx, tx, and interrupt on complete reception of a byte
|
||||
UCSR0B |= (1<<RXEN0 | 1<<TXEN0 | 1<<RXCIE0);
|
||||
// enable rx, tx, and interrupt on complete reception of a byte
|
||||
UCSR0B |= (1 << RXEN0 | 1 << TXEN0 | 1 << RXCIE0);
|
||||
|
||||
// defaults to 8-bit, no parity, 1 stop bit
|
||||
// defaults to 8-bit, no parity, 1 stop bit
|
||||
}
|
||||
|
||||
|
||||
// Writes one byte to the TX serial buffer. Called by main program.
|
||||
void serial_write(uint8_t data) {
|
||||
// Calculate next head
|
||||
uint8_t next_head = serial_tx_buffer_head + 1;
|
||||
if (next_head == TX_RING_BUFFER) { next_head = 0; }
|
||||
// Calculate next head
|
||||
uint8_t next_head = serial_tx_buffer_head + 1;
|
||||
if (next_head == TX_RING_BUFFER) {
|
||||
next_head = 0;
|
||||
}
|
||||
|
||||
// Wait until there is space in the buffer
|
||||
while (next_head == serial_tx_buffer_tail) {
|
||||
// TODO: Restructure st_prep_buffer() calls to be executed here during a long print.
|
||||
if (sys_rt_exec_state & EXEC_RESET) { return; } // Only check for abort to avoid an endless loop.
|
||||
}
|
||||
// Wait until there is space in the buffer
|
||||
while (next_head == serial_tx_buffer_tail) {
|
||||
// TODO: Restructure st_prep_buffer() calls to be executed here during a long print.
|
||||
if (sys_rt_exec_state & EXEC_RESET) {
|
||||
return;
|
||||
} // Only check for abort to avoid an endless loop.
|
||||
}
|
||||
|
||||
// Store data and advance head
|
||||
serial_tx_buffer[serial_tx_buffer_head] = data;
|
||||
serial_tx_buffer_head = next_head;
|
||||
// Store data and advance head
|
||||
serial_tx_buffer[serial_tx_buffer_head] = data;
|
||||
serial_tx_buffer_head = next_head;
|
||||
|
||||
// Enable Data Register Empty Interrupt to make sure tx-streaming is running
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
// Enable Data Register Empty Interrupt to make sure tx-streaming is running
|
||||
UCSR0B |= (1 << UDRIE0);
|
||||
}
|
||||
|
||||
|
||||
// Data Register Empty Interrupt handler
|
||||
ISR(SERIAL_UDRE)
|
||||
{
|
||||
uint8_t tail = serial_tx_buffer_tail; // Temporary serial_tx_buffer_tail (to optimize for volatile)
|
||||
ISR(SERIAL_UDRE) {
|
||||
uint8_t tail = serial_tx_buffer_tail; // Temporary serial_tx_buffer_tail (to optimize for volatile)
|
||||
|
||||
// Send a byte from the buffer
|
||||
UDR0 = serial_tx_buffer[tail];
|
||||
// Send a byte from the buffer
|
||||
UDR0 = serial_tx_buffer[tail];
|
||||
|
||||
// Update tail position
|
||||
tail++;
|
||||
if (tail == TX_RING_BUFFER) { tail = 0; }
|
||||
// Update tail position
|
||||
tail++;
|
||||
if (tail == TX_RING_BUFFER) {
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
serial_tx_buffer_tail = tail;
|
||||
serial_tx_buffer_tail = tail;
|
||||
|
||||
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
|
||||
if (tail == serial_tx_buffer_head) { UCSR0B &= ~(1 << UDRIE0); }
|
||||
// Turn off Data Register Empty Interrupt to stop tx-streaming if this concludes the transfer
|
||||
if (tail == serial_tx_buffer_head) {
|
||||
UCSR0B &= ~(1 << UDRIE0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fetches the first byte in the serial read buffer. Called by main program.
|
||||
uint8_t serial_read()
|
||||
{
|
||||
uint8_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile)
|
||||
if (serial_rx_buffer_head == tail) {
|
||||
return SERIAL_NO_DATA;
|
||||
} else {
|
||||
uint8_t data = serial_rx_buffer[tail];
|
||||
uint8_t serial_read() {
|
||||
uint8_t tail = serial_rx_buffer_tail; // Temporary serial_rx_buffer_tail (to optimize for volatile)
|
||||
if (serial_rx_buffer_head == tail) {
|
||||
return SERIAL_NO_DATA;
|
||||
} else {
|
||||
uint8_t data = serial_rx_buffer[tail];
|
||||
|
||||
tail++;
|
||||
if (tail == RX_RING_BUFFER) { tail = 0; }
|
||||
serial_rx_buffer_tail = tail;
|
||||
tail++;
|
||||
if (tail == RX_RING_BUFFER) {
|
||||
tail = 0;
|
||||
}
|
||||
serial_rx_buffer_tail = tail;
|
||||
|
||||
return data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
ISR(SERIAL_RX) {
|
||||
uint8_t data = UDR0;
|
||||
uint8_t next_head;
|
||||
|
||||
ISR(SERIAL_RX)
|
||||
{
|
||||
uint8_t data = UDR0;
|
||||
uint8_t next_head;
|
||||
|
||||
// Pick off realtime command characters directly from the serial stream. These characters are
|
||||
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
||||
switch (data) {
|
||||
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
|
||||
// Pick off realtime command characters directly from the serial stream. These characters are
|
||||
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
||||
switch (data) {
|
||||
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
|
||||
case CMD_STATUS_REPORT: system_set_exec_state_flag(EXEC_STATUS_REPORT); break; // Set as true
|
||||
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
|
||||
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
|
||||
default :
|
||||
if (data > 0x7F) { // Real-time control characters are extended ACSII only.
|
||||
switch(data) {
|
||||
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
|
||||
case CMD_JOG_CANCEL:
|
||||
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
|
||||
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
|
||||
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
|
||||
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
|
||||
default:
|
||||
if (data > 0x7F) { // Real-time control characters are extended ACSII only.
|
||||
switch (data) {
|
||||
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
|
||||
case CMD_JOG_CANCEL:
|
||||
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
|
||||
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case CMD_DEBUG_REPORT: {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
bit_true(sys_rt_exec_debug, EXEC_DEBUG_REPORT);
|
||||
SREG = sreg;
|
||||
} break;
|
||||
#endif
|
||||
case CMD_FEED_OVR_RESET: system_set_exec_motion_override_flag(EXEC_FEED_OVR_RESET); break;
|
||||
case CMD_FEED_OVR_COARSE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_PLUS); break;
|
||||
case CMD_FEED_OVR_COARSE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_MINUS); break;
|
||||
case CMD_FEED_OVR_FINE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_PLUS); break;
|
||||
case CMD_FEED_OVR_FINE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_MINUS); break;
|
||||
case CMD_RAPID_OVR_RESET: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_RESET); break;
|
||||
case CMD_RAPID_OVR_MEDIUM: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_MEDIUM); break;
|
||||
case CMD_RAPID_OVR_LOW: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_LOW); break;
|
||||
case CMD_SPINDLE_OVR_RESET: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_RESET); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_PLUS:
|
||||
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_PLUS);
|
||||
break;
|
||||
case CMD_SPINDLE_OVR_COARSE_MINUS:
|
||||
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_MINUS);
|
||||
break;
|
||||
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_MINUS:
|
||||
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS);
|
||||
break;
|
||||
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
|
||||
case CMD_COOLANT_FLOOD_OVR_TOGGLE:
|
||||
system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE);
|
||||
break;
|
||||
#ifdef ENABLE_M7
|
||||
case CMD_COOLANT_MIST_OVR_TOGGLE:
|
||||
system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
// Throw away any unfound extended-ASCII character by not passing it to the serial buffer.
|
||||
} else { // Write character to buffer
|
||||
next_head = serial_rx_buffer_head + 1;
|
||||
if (next_head == RX_RING_BUFFER) {
|
||||
next_head = 0;
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case CMD_DEBUG_REPORT: {uint8_t sreg = SREG; cli(); bit_true(sys_rt_exec_debug,EXEC_DEBUG_REPORT); SREG = sreg;} break;
|
||||
#endif
|
||||
case CMD_FEED_OVR_RESET: system_set_exec_motion_override_flag(EXEC_FEED_OVR_RESET); break;
|
||||
case CMD_FEED_OVR_COARSE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_PLUS); break;
|
||||
case CMD_FEED_OVR_COARSE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_MINUS); break;
|
||||
case CMD_FEED_OVR_FINE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_PLUS); break;
|
||||
case CMD_FEED_OVR_FINE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_MINUS); break;
|
||||
case CMD_RAPID_OVR_RESET: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_RESET); break;
|
||||
case CMD_RAPID_OVR_MEDIUM: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_MEDIUM); break;
|
||||
case CMD_RAPID_OVR_LOW: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_LOW); break;
|
||||
case CMD_SPINDLE_OVR_RESET: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_RESET); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
|
||||
case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break;
|
||||
#ifdef ENABLE_M7
|
||||
case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break;
|
||||
#endif
|
||||
}
|
||||
// Throw away any unfound extended-ASCII character by not passing it to the serial buffer.
|
||||
} else { // Write character to buffer
|
||||
next_head = serial_rx_buffer_head + 1;
|
||||
if (next_head == RX_RING_BUFFER) { next_head = 0; }
|
||||
|
||||
// Write data to buffer unless it is full.
|
||||
if (next_head != serial_rx_buffer_tail) {
|
||||
serial_rx_buffer[serial_rx_buffer_head] = data;
|
||||
serial_rx_buffer_head = next_head;
|
||||
// Write data to buffer unless it is full.
|
||||
if (next_head != serial_rx_buffer_tail) {
|
||||
serial_rx_buffer[serial_rx_buffer_head] = data;
|
||||
serial_rx_buffer_head = next_head;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void serial_reset_read_buffer()
|
||||
{
|
||||
serial_rx_buffer_tail = serial_rx_buffer_head;
|
||||
void serial_reset_read_buffer() {
|
||||
serial_rx_buffer_tail = serial_rx_buffer_head;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,21 +22,19 @@
|
|||
#ifndef serial_h
|
||||
#define serial_h
|
||||
|
||||
|
||||
#ifndef RX_BUFFER_SIZE
|
||||
#define RX_BUFFER_SIZE 128
|
||||
#define RX_BUFFER_SIZE 128
|
||||
#endif
|
||||
#ifndef TX_BUFFER_SIZE
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define TX_BUFFER_SIZE 112
|
||||
#else
|
||||
#define TX_BUFFER_SIZE 104
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define TX_BUFFER_SIZE 112
|
||||
#else
|
||||
#define TX_BUFFER_SIZE 104
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SERIAL_NO_DATA 0xff
|
||||
|
||||
|
||||
void serial_init();
|
||||
|
||||
// Writes one byte to the TX serial buffer. Called by main program.
|
||||
|
|
|
|||
493
grbl/settings.c
493
grbl/settings.c
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
settings_t settings;
|
||||
|
||||
const __flash settings_t defaults = {\
|
||||
const __flash settings_t defaults = {
|
||||
.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS,
|
||||
.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME,
|
||||
.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK,
|
||||
|
|
@ -38,14 +38,10 @@ const __flash settings_t defaults = {\
|
|||
.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE,
|
||||
.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY,
|
||||
.homing_pulloff = DEFAULT_HOMING_PULLOFF,
|
||||
.flags = (DEFAULT_REPORT_INCHES << BIT_REPORT_INCHES) | \
|
||||
(DEFAULT_LASER_MODE << BIT_LASER_MODE) | \
|
||||
(DEFAULT_INVERT_ST_ENABLE << BIT_INVERT_ST_ENABLE) | \
|
||||
(DEFAULT_HARD_LIMIT_ENABLE << BIT_HARD_LIMIT_ENABLE) | \
|
||||
(DEFAULT_HOMING_ENABLE << BIT_HOMING_ENABLE) | \
|
||||
(DEFAULT_SOFT_LIMIT_ENABLE << BIT_SOFT_LIMIT_ENABLE) | \
|
||||
(DEFAULT_INVERT_LIMIT_PINS << BIT_INVERT_LIMIT_PINS) | \
|
||||
(DEFAULT_INVERT_PROBE_PIN << BIT_INVERT_PROBE_PIN),
|
||||
.flags = (DEFAULT_REPORT_INCHES << BIT_REPORT_INCHES) | (DEFAULT_LASER_MODE << BIT_LASER_MODE) |
|
||||
(DEFAULT_INVERT_ST_ENABLE << BIT_INVERT_ST_ENABLE) | (DEFAULT_HARD_LIMIT_ENABLE << BIT_HARD_LIMIT_ENABLE) |
|
||||
(DEFAULT_HOMING_ENABLE << BIT_HOMING_ENABLE) | (DEFAULT_SOFT_LIMIT_ENABLE << BIT_SOFT_LIMIT_ENABLE) |
|
||||
(DEFAULT_INVERT_LIMIT_PINS << BIT_INVERT_LIMIT_PINS) | (DEFAULT_INVERT_PROBE_PIN << BIT_INVERT_PROBE_PIN),
|
||||
.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM,
|
||||
.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM,
|
||||
.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM,
|
||||
|
|
@ -59,282 +55,313 @@ const __flash settings_t defaults = {\
|
|||
.max_travel[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL),
|
||||
.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL)};
|
||||
|
||||
|
||||
// Method to store startup lines into EEPROM
|
||||
void settings_store_startup_line(uint8_t n, char *line)
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
protocol_buffer_synchronize(); // A startup line may contain a motion and be executing.
|
||||
#endif
|
||||
uint32_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
|
||||
memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
|
||||
void settings_store_startup_line(uint8_t n, char *line) {
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
protocol_buffer_synchronize(); // A startup line may contain a motion and be executing.
|
||||
#endif
|
||||
uint32_t addr = n * (LINE_BUFFER_SIZE + 1) + EEPROM_ADDR_STARTUP_BLOCK;
|
||||
memcpy_to_eeprom_with_checksum(addr, (char *)line, LINE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
// Method to store build info into EEPROM
|
||||
// NOTE: This function can only be called in IDLE state.
|
||||
void settings_store_build_info(char *line)
|
||||
{
|
||||
// Build info can only be stored when state is IDLE.
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_BUILD_INFO,(char*)line, LINE_BUFFER_SIZE);
|
||||
void settings_store_build_info(char *line) {
|
||||
// Build info can only be stored when state is IDLE.
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_BUILD_INFO, (char *)line, LINE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
// Method to store coord data parameters into EEPROM
|
||||
void settings_write_coord_data(uint8_t coord_select, float *coord_data)
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
void settings_write_coord_data(uint8_t coord_select, float *coord_data) {
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
protocol_buffer_synchronize();
|
||||
#endif
|
||||
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
|
||||
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
|
||||
#endif
|
||||
uint32_t addr = coord_select * (sizeof(float) * N_AXIS + 1) + EEPROM_ADDR_PARAMETERS;
|
||||
memcpy_to_eeprom_with_checksum(addr, (char *)coord_data, sizeof(float) * N_AXIS);
|
||||
}
|
||||
|
||||
|
||||
// Method to store Grbl global settings struct and version number into EEPROM
|
||||
// NOTE: This function can only be called in IDLE state.
|
||||
void write_global_settings()
|
||||
{
|
||||
eeprom_put_char(0, SETTINGS_VERSION);
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
|
||||
void write_global_settings() {
|
||||
eeprom_put_char(0, SETTINGS_VERSION);
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char *)&settings, sizeof(settings_t));
|
||||
}
|
||||
|
||||
|
||||
// Method to restore EEPROM-saved Grbl global settings back to defaults.
|
||||
void settings_restore(uint8_t restore_flag) {
|
||||
if (restore_flag & SETTINGS_RESTORE_DEFAULTS) {
|
||||
settings = defaults;
|
||||
write_global_settings();
|
||||
}
|
||||
if (restore_flag & SETTINGS_RESTORE_DEFAULTS) {
|
||||
settings = defaults;
|
||||
write_global_settings();
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_PARAMETERS) {
|
||||
uint8_t idx;
|
||||
float coord_data[N_AXIS];
|
||||
memset(&coord_data, 0, sizeof(coord_data));
|
||||
for (idx=0; idx <= SETTING_INDEX_NCOORD; idx++) { settings_write_coord_data(idx, coord_data); }
|
||||
}
|
||||
if (restore_flag & SETTINGS_RESTORE_PARAMETERS) {
|
||||
uint8_t idx;
|
||||
float coord_data[N_AXIS];
|
||||
memset(&coord_data, 0, sizeof(coord_data));
|
||||
for (idx = 0; idx <= SETTING_INDEX_NCOORD; idx++) {
|
||||
settings_write_coord_data(idx, coord_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_STARTUP_LINES) {
|
||||
#if N_STARTUP_LINE > 0
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK, 0);
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK+1, 0); // Checksum
|
||||
#endif
|
||||
#if N_STARTUP_LINE > 1
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK+(LINE_BUFFER_SIZE+1), 0);
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK+(LINE_BUFFER_SIZE+2), 0); // Checksum
|
||||
#endif
|
||||
}
|
||||
if (restore_flag & SETTINGS_RESTORE_STARTUP_LINES) {
|
||||
#if N_STARTUP_LINE > 0
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK, 0);
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK + 1, 0); // Checksum
|
||||
#endif
|
||||
#if N_STARTUP_LINE > 1
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK + (LINE_BUFFER_SIZE + 1), 0);
|
||||
eeprom_put_char(EEPROM_ADDR_STARTUP_BLOCK + (LINE_BUFFER_SIZE + 2), 0); // Checksum
|
||||
#endif
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_BUILD_INFO) {
|
||||
eeprom_put_char(EEPROM_ADDR_BUILD_INFO , 0);
|
||||
eeprom_put_char(EEPROM_ADDR_BUILD_INFO+1 , 0); // Checksum
|
||||
}
|
||||
if (restore_flag & SETTINGS_RESTORE_BUILD_INFO) {
|
||||
eeprom_put_char(EEPROM_ADDR_BUILD_INFO, 0);
|
||||
eeprom_put_char(EEPROM_ADDR_BUILD_INFO + 1, 0); // Checksum
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reads startup line from EEPROM. Updated pointed line string data.
|
||||
uint8_t settings_read_startup_line(uint8_t n, char *line)
|
||||
{
|
||||
uint32_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_startup_line(n, line);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
uint8_t settings_read_startup_line(uint8_t n, char *line) {
|
||||
uint32_t addr = n * (LINE_BUFFER_SIZE + 1) + EEPROM_ADDR_STARTUP_BLOCK;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char *)line, addr, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_startup_line(n, line);
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// Reads startup line from EEPROM. Updated pointed line string data.
|
||||
uint8_t settings_read_build_info(char *line)
|
||||
{
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)line, EEPROM_ADDR_BUILD_INFO, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_build_info(line);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
uint8_t settings_read_build_info(char *line) {
|
||||
if (!(memcpy_from_eeprom_with_checksum((char *)line, EEPROM_ADDR_BUILD_INFO, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_build_info(line);
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// Read selected coordinate data from EEPROM. Updates pointed coord_data value.
|
||||
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
|
||||
{
|
||||
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
|
||||
// Reset with default zero vector
|
||||
clear_vector_float(coord_data);
|
||||
settings_write_coord_data(coord_select,coord_data);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data) {
|
||||
uint32_t addr = coord_select * (sizeof(float) * N_AXIS + 1) + EEPROM_ADDR_PARAMETERS;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char *)coord_data, addr, sizeof(float) * N_AXIS))) {
|
||||
// Reset with default zero vector
|
||||
clear_vector_float(coord_data);
|
||||
settings_write_coord_data(coord_select, coord_data);
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// Reads Grbl global settings struct from EEPROM.
|
||||
uint8_t read_global_settings() {
|
||||
// Check version-byte of eeprom
|
||||
uint8_t version = eeprom_get_char(0);
|
||||
if (version == SETTINGS_VERSION) {
|
||||
// Read settings-record and check checksum
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
|
||||
return(false);
|
||||
// Check version-byte of eeprom
|
||||
uint8_t version = eeprom_get_char(0);
|
||||
if (version == SETTINGS_VERSION) {
|
||||
// Read settings-record and check checksum
|
||||
if (!(memcpy_from_eeprom_with_checksum((char *)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
return (false);
|
||||
}
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
// A helper method to set settings from command line
|
||||
uint8_t settings_store_global_setting(uint8_t parameter, float value) {
|
||||
if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); }
|
||||
if (parameter >= AXIS_SETTINGS_START_VAL) {
|
||||
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
|
||||
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
|
||||
parameter -= AXIS_SETTINGS_START_VAL;
|
||||
uint8_t set_idx = 0;
|
||||
while (set_idx < AXIS_N_SETTINGS) {
|
||||
if (parameter < N_AXIS) {
|
||||
// Valid axis setting found.
|
||||
switch (set_idx) {
|
||||
case 0:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value*settings.max_rate[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
|
||||
#endif
|
||||
settings.steps_per_mm[parameter] = value;
|
||||
break;
|
||||
case 1:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
|
||||
#endif
|
||||
settings.max_rate[parameter] = value;
|
||||
break;
|
||||
case 2: settings.acceleration[parameter] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
|
||||
case 3: settings.max_travel[parameter] = -value; break; // Store as negative for grbl internal use.
|
||||
}
|
||||
break; // Exit while-loop after setting has been configured and proceed to the EEPROM write call.
|
||||
} else {
|
||||
set_idx++;
|
||||
// If axis index greater than N_AXIS or setting index greater than number of axis settings, error out.
|
||||
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS)) { return(STATUS_INVALID_STATEMENT); }
|
||||
parameter -= AXIS_SETTINGS_INCREMENT;
|
||||
}
|
||||
if (value < 0.0) {
|
||||
return (STATUS_NEGATIVE_VALUE);
|
||||
}
|
||||
} else {
|
||||
// Store non-axis Grbl settings
|
||||
uint8_t int_value = trunc(value);
|
||||
switch(parameter) {
|
||||
case 0:
|
||||
if (int_value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
|
||||
settings.pulse_microseconds = int_value; break;
|
||||
case 1: settings.stepper_idle_lock_time = int_value; break;
|
||||
case 2:
|
||||
settings.step_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 3:
|
||||
settings.dir_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 4: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
|
||||
break;
|
||||
case 5: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
|
||||
break;
|
||||
case 6: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_PROBE_PIN; }
|
||||
probe_configure_invert_mask(false);
|
||||
break;
|
||||
case 10: settings.status_report_mask = int_value; break;
|
||||
case 11: settings.junction_deviation = value; break;
|
||||
case 12: settings.arc_tolerance = value; break;
|
||||
case 13:
|
||||
if (int_value) { settings.flags |= BITFLAG_REPORT_INCHES; }
|
||||
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
|
||||
system_flag_wco_change(); // Make sure WCO is immediately updated.
|
||||
break;
|
||||
case 20:
|
||||
if (int_value) {
|
||||
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
|
||||
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
|
||||
break;
|
||||
case 21:
|
||||
if (int_value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
|
||||
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
|
||||
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
|
||||
break;
|
||||
case 22:
|
||||
if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
|
||||
else {
|
||||
settings.flags &= ~BITFLAG_HOMING_ENABLE;
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
|
||||
if (parameter >= AXIS_SETTINGS_START_VAL) {
|
||||
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
|
||||
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
|
||||
parameter -= AXIS_SETTINGS_START_VAL;
|
||||
uint8_t set_idx = 0;
|
||||
while (set_idx < AXIS_N_SETTINGS) {
|
||||
if (parameter < N_AXIS) {
|
||||
// Valid axis setting found.
|
||||
switch (set_idx) {
|
||||
case 0:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value * settings.max_rate[parameter] > (MAX_STEP_RATE_HZ * 60.0)) {
|
||||
return (STATUS_MAX_STEP_RATE_EXCEEDED);
|
||||
}
|
||||
#endif
|
||||
settings.steps_per_mm[parameter] = value;
|
||||
break;
|
||||
case 1:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value * settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ * 60.0)) {
|
||||
return (STATUS_MAX_STEP_RATE_EXCEEDED);
|
||||
}
|
||||
#endif
|
||||
settings.max_rate[parameter] = value;
|
||||
break;
|
||||
case 2:
|
||||
settings.acceleration[parameter] = value * 60 * 60;
|
||||
break; // Convert to mm/min^2 for grbl internal use.
|
||||
case 3: settings.max_travel[parameter] = -value; break; // Store as negative for grbl internal use.
|
||||
}
|
||||
break; // Exit while-loop after setting has been configured and proceed to the EEPROM write call.
|
||||
} else {
|
||||
set_idx++;
|
||||
// If axis index greater than N_AXIS or setting index greater than number of axis settings, error out.
|
||||
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS)) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
parameter -= AXIS_SETTINGS_INCREMENT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Store non-axis Grbl settings
|
||||
uint8_t int_value = trunc(value);
|
||||
switch (parameter) {
|
||||
case 0:
|
||||
if (int_value < 3) {
|
||||
return (STATUS_SETTING_STEP_PULSE_MIN);
|
||||
}
|
||||
settings.pulse_microseconds = int_value;
|
||||
break;
|
||||
case 1: settings.stepper_idle_lock_time = int_value; break;
|
||||
case 2:
|
||||
settings.step_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 3:
|
||||
settings.dir_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 4: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_INVERT_ST_ENABLE;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_INVERT_ST_ENABLE;
|
||||
}
|
||||
break;
|
||||
case 5: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_INVERT_LIMIT_PINS;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS;
|
||||
}
|
||||
break;
|
||||
case 6: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_INVERT_PROBE_PIN;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_INVERT_PROBE_PIN;
|
||||
}
|
||||
probe_configure_invert_mask(false);
|
||||
break;
|
||||
case 10: settings.status_report_mask = int_value; break;
|
||||
case 11: settings.junction_deviation = value; break;
|
||||
case 12: settings.arc_tolerance = value; break;
|
||||
case 13:
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_REPORT_INCHES;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_REPORT_INCHES;
|
||||
}
|
||||
system_flag_wco_change(); // Make sure WCO is immediately updated.
|
||||
break;
|
||||
case 20:
|
||||
if (int_value) {
|
||||
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) {
|
||||
return (STATUS_SOFT_LIMIT_ERROR);
|
||||
}
|
||||
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_HARD_LIMIT_ENABLE;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE;
|
||||
}
|
||||
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
|
||||
break;
|
||||
case 22:
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_HOMING_ENABLE;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_HOMING_ENABLE;
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
|
||||
}
|
||||
break;
|
||||
case 23: settings.homing_dir_mask = int_value; break;
|
||||
case 24: settings.homing_feed_rate = value; break;
|
||||
case 25: settings.homing_seek_rate = value; break;
|
||||
case 26: settings.homing_debounce_delay = int_value; break;
|
||||
case 27: settings.homing_pulloff = value; break;
|
||||
case 30:
|
||||
settings.rpm_max = value;
|
||||
spindle_init();
|
||||
break; // Re-initialize spindle rpm calibration
|
||||
case 31:
|
||||
settings.rpm_min = value;
|
||||
spindle_init();
|
||||
break; // Re-initialize spindle rpm calibration
|
||||
case 32:
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
if (int_value) {
|
||||
settings.flags |= BITFLAG_LASER_MODE;
|
||||
} else {
|
||||
settings.flags &= ~BITFLAG_LASER_MODE;
|
||||
}
|
||||
#else
|
||||
return (STATUS_SETTING_DISABLED_LASER);
|
||||
#endif
|
||||
break;
|
||||
default: return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
break;
|
||||
case 23: settings.homing_dir_mask = int_value; break;
|
||||
case 24: settings.homing_feed_rate = value; break;
|
||||
case 25: settings.homing_seek_rate = value; break;
|
||||
case 26: settings.homing_debounce_delay = int_value; break;
|
||||
case 27: settings.homing_pulloff = value; break;
|
||||
case 30: settings.rpm_max = value; spindle_init(); break; // Re-initialize spindle rpm calibration
|
||||
case 31: settings.rpm_min = value; spindle_init(); break; // Re-initialize spindle rpm calibration
|
||||
case 32:
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
if (int_value) { settings.flags |= BITFLAG_LASER_MODE; }
|
||||
else { settings.flags &= ~BITFLAG_LASER_MODE; }
|
||||
#else
|
||||
return(STATUS_SETTING_DISABLED_LASER);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
}
|
||||
write_global_settings();
|
||||
return(STATUS_OK);
|
||||
write_global_settings();
|
||||
return (STATUS_OK);
|
||||
}
|
||||
|
||||
|
||||
// Initialize the config subsystem
|
||||
void settings_init() {
|
||||
if(!read_global_settings()) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL);
|
||||
settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
|
||||
report_grbl_settings();
|
||||
}
|
||||
if (!read_global_settings()) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL);
|
||||
settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
|
||||
report_grbl_settings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns step pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_step_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
if ( axis_idx == X_AXIS ) { return((1<<X_STEP_BIT)); }
|
||||
if ( axis_idx == Y_AXIS ) { return((1<<Y_STEP_BIT)); }
|
||||
return((1<<Z_STEP_BIT));
|
||||
uint8_t get_step_pin_mask(uint8_t axis_idx) {
|
||||
if (axis_idx == X_AXIS) {
|
||||
return ((1 << X_STEP_BIT));
|
||||
}
|
||||
if (axis_idx == Y_AXIS) {
|
||||
return ((1 << Y_STEP_BIT));
|
||||
}
|
||||
return ((1 << Z_STEP_BIT));
|
||||
}
|
||||
|
||||
|
||||
// Returns direction pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_direction_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
if ( axis_idx == X_AXIS ) { return((1<<X_DIRECTION_BIT)); }
|
||||
if ( axis_idx == Y_AXIS ) { return((1<<Y_DIRECTION_BIT)); }
|
||||
return((1<<Z_DIRECTION_BIT));
|
||||
uint8_t get_direction_pin_mask(uint8_t axis_idx) {
|
||||
if (axis_idx == X_AXIS) {
|
||||
return ((1 << X_DIRECTION_BIT));
|
||||
}
|
||||
if (axis_idx == Y_AXIS) {
|
||||
return ((1 << Y_DIRECTION_BIT));
|
||||
}
|
||||
return ((1 << Z_DIRECTION_BIT));
|
||||
}
|
||||
|
||||
|
||||
// Returns limit pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_limit_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
if ( axis_idx == X_AXIS ) { return((1<<X_LIMIT_BIT)); }
|
||||
if ( axis_idx == Y_AXIS ) { return((1<<Y_LIMIT_BIT)); }
|
||||
return((1<<Z_LIMIT_BIT));
|
||||
uint8_t get_limit_pin_mask(uint8_t axis_idx) {
|
||||
if (axis_idx == X_AXIS) {
|
||||
return ((1 << X_LIMIT_BIT));
|
||||
}
|
||||
if (axis_idx == Y_AXIS) {
|
||||
return ((1 << Y_LIMIT_BIT));
|
||||
}
|
||||
return ((1 << Z_LIMIT_BIT));
|
||||
}
|
||||
|
|
|
|||
113
grbl/settings.h
113
grbl/settings.h
|
|
@ -24,93 +24,93 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl
|
||||
// when firmware is upgraded. Always stored in byte 0 of eeprom
|
||||
#define SETTINGS_VERSION 10 // NOTE: Check settings_reset() when moving to next version.
|
||||
#define SETTINGS_VERSION 10 // NOTE: Check settings_reset() when moving to next version.
|
||||
|
||||
// Define bit flag masks for the boolean settings in settings.flag.
|
||||
#define BIT_REPORT_INCHES 0
|
||||
#define BIT_LASER_MODE 1
|
||||
#define BIT_INVERT_ST_ENABLE 2
|
||||
#define BIT_HARD_LIMIT_ENABLE 3
|
||||
#define BIT_HOMING_ENABLE 4
|
||||
#define BIT_SOFT_LIMIT_ENABLE 5
|
||||
#define BIT_INVERT_LIMIT_PINS 6
|
||||
#define BIT_INVERT_PROBE_PIN 7
|
||||
#define BIT_REPORT_INCHES 0
|
||||
#define BIT_LASER_MODE 1
|
||||
#define BIT_INVERT_ST_ENABLE 2
|
||||
#define BIT_HARD_LIMIT_ENABLE 3
|
||||
#define BIT_HOMING_ENABLE 4
|
||||
#define BIT_SOFT_LIMIT_ENABLE 5
|
||||
#define BIT_INVERT_LIMIT_PINS 6
|
||||
#define BIT_INVERT_PROBE_PIN 7
|
||||
|
||||
#define BITFLAG_REPORT_INCHES bit(BIT_REPORT_INCHES)
|
||||
#define BITFLAG_LASER_MODE bit(BIT_LASER_MODE)
|
||||
#define BITFLAG_INVERT_ST_ENABLE bit(BIT_INVERT_ST_ENABLE)
|
||||
#define BITFLAG_HARD_LIMIT_ENABLE bit(BIT_HARD_LIMIT_ENABLE)
|
||||
#define BITFLAG_HOMING_ENABLE bit(BIT_HOMING_ENABLE)
|
||||
#define BITFLAG_SOFT_LIMIT_ENABLE bit(BIT_SOFT_LIMIT_ENABLE)
|
||||
#define BITFLAG_INVERT_LIMIT_PINS bit(BIT_INVERT_LIMIT_PINS)
|
||||
#define BITFLAG_INVERT_PROBE_PIN bit(BIT_INVERT_PROBE_PIN)
|
||||
#define BITFLAG_REPORT_INCHES bit(BIT_REPORT_INCHES)
|
||||
#define BITFLAG_LASER_MODE bit(BIT_LASER_MODE)
|
||||
#define BITFLAG_INVERT_ST_ENABLE bit(BIT_INVERT_ST_ENABLE)
|
||||
#define BITFLAG_HARD_LIMIT_ENABLE bit(BIT_HARD_LIMIT_ENABLE)
|
||||
#define BITFLAG_HOMING_ENABLE bit(BIT_HOMING_ENABLE)
|
||||
#define BITFLAG_SOFT_LIMIT_ENABLE bit(BIT_SOFT_LIMIT_ENABLE)
|
||||
#define BITFLAG_INVERT_LIMIT_PINS bit(BIT_INVERT_LIMIT_PINS)
|
||||
#define BITFLAG_INVERT_PROBE_PIN bit(BIT_INVERT_PROBE_PIN)
|
||||
|
||||
// Define status reporting boolean enable bit flags in settings.status_report_mask
|
||||
#define BITFLAG_RT_STATUS_POSITION_TYPE bit(0)
|
||||
#define BITFLAG_RT_STATUS_BUFFER_STATE bit(1)
|
||||
#define BITFLAG_RT_STATUS_POSITION_TYPE bit(0)
|
||||
#define BITFLAG_RT_STATUS_BUFFER_STATE bit(1)
|
||||
|
||||
// Define settings restore bitflags.
|
||||
#define SETTINGS_RESTORE_DEFAULTS bit(0)
|
||||
#define SETTINGS_RESTORE_PARAMETERS bit(1)
|
||||
#define SETTINGS_RESTORE_DEFAULTS bit(0)
|
||||
#define SETTINGS_RESTORE_PARAMETERS bit(1)
|
||||
#define SETTINGS_RESTORE_STARTUP_LINES bit(2)
|
||||
#define SETTINGS_RESTORE_BUILD_INFO bit(3)
|
||||
#define SETTINGS_RESTORE_BUILD_INFO bit(3)
|
||||
#ifndef SETTINGS_RESTORE_ALL
|
||||
#define SETTINGS_RESTORE_ALL 0xFF // All bitflags
|
||||
#define SETTINGS_RESTORE_ALL 0xFF // All bitflags
|
||||
#endif
|
||||
|
||||
// Define EEPROM memory address location values for Grbl settings and parameters
|
||||
// NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and
|
||||
// the startup script. The lower half contains the global settings and space for future
|
||||
// developments.
|
||||
#define EEPROM_ADDR_GLOBAL 1U
|
||||
#define EEPROM_ADDR_PARAMETERS 512U
|
||||
#define EEPROM_ADDR_STARTUP_BLOCK 768U
|
||||
#define EEPROM_ADDR_BUILD_INFO 942U
|
||||
#define EEPROM_ADDR_GLOBAL 1U
|
||||
#define EEPROM_ADDR_PARAMETERS 512U
|
||||
#define EEPROM_ADDR_STARTUP_BLOCK 768U
|
||||
#define EEPROM_ADDR_BUILD_INFO 942U
|
||||
|
||||
// Define EEPROM address indexing for coordinate parameters
|
||||
#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1)
|
||||
#define SETTING_INDEX_NCOORD N_COORDINATE_SYSTEM+1 // Total number of system stored (from index 0)
|
||||
#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1)
|
||||
#define SETTING_INDEX_NCOORD N_COORDINATE_SYSTEM + 1 // Total number of system stored (from index 0)
|
||||
// NOTE: Work coordinate indices are (0=G54, 1=G55, ... , 6=G59)
|
||||
#define SETTING_INDEX_G28 N_COORDINATE_SYSTEM // Home position 1
|
||||
#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2
|
||||
#define SETTING_INDEX_G28 N_COORDINATE_SYSTEM // Home position 1
|
||||
#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM + 1 // Home position 2
|
||||
// #define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset (G92.2,G92.3 not supported)
|
||||
|
||||
// Define Grbl axis settings numbering scheme. Starts at START_VAL, every INCREMENT, over N_SETTINGS.
|
||||
#define AXIS_N_SETTINGS 4
|
||||
#define AXIS_SETTINGS_START_VAL 100 // NOTE: Reserving settings values >= 100 for axis settings. Up to 255.
|
||||
#define AXIS_SETTINGS_INCREMENT 10 // Must be greater than the number of axis settings
|
||||
#define AXIS_N_SETTINGS 4
|
||||
#define AXIS_SETTINGS_START_VAL 100 // NOTE: Reserving settings values >= 100 for axis settings. Up to 255.
|
||||
#define AXIS_SETTINGS_INCREMENT 10 // Must be greater than the number of axis settings
|
||||
|
||||
// Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards)
|
||||
typedef struct {
|
||||
// Axis settings
|
||||
float steps_per_mm[N_AXIS];
|
||||
float max_rate[N_AXIS];
|
||||
float acceleration[N_AXIS];
|
||||
float max_travel[N_AXIS];
|
||||
// Axis settings
|
||||
float steps_per_mm[N_AXIS];
|
||||
float max_rate[N_AXIS];
|
||||
float acceleration[N_AXIS];
|
||||
float max_travel[N_AXIS];
|
||||
|
||||
// Remaining Grbl settings
|
||||
uint8_t pulse_microseconds;
|
||||
uint8_t step_invert_mask;
|
||||
uint8_t dir_invert_mask;
|
||||
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
|
||||
uint8_t status_report_mask; // Mask to indicate desired report data.
|
||||
float junction_deviation;
|
||||
float arc_tolerance;
|
||||
// Remaining Grbl settings
|
||||
uint8_t pulse_microseconds;
|
||||
uint8_t step_invert_mask;
|
||||
uint8_t dir_invert_mask;
|
||||
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
|
||||
uint8_t status_report_mask; // Mask to indicate desired report data.
|
||||
float junction_deviation;
|
||||
float arc_tolerance;
|
||||
|
||||
float rpm_max;
|
||||
float rpm_min;
|
||||
float rpm_max;
|
||||
float rpm_min;
|
||||
|
||||
uint8_t flags; // Contains default boolean settings
|
||||
uint8_t flags; // Contains default boolean settings
|
||||
|
||||
uint8_t homing_dir_mask;
|
||||
float homing_feed_rate;
|
||||
float homing_seek_rate;
|
||||
uint16_t homing_debounce_delay;
|
||||
float homing_pulloff;
|
||||
uint8_t homing_dir_mask;
|
||||
float homing_feed_rate;
|
||||
float homing_seek_rate;
|
||||
uint16_t homing_debounce_delay;
|
||||
float homing_pulloff;
|
||||
} settings_t;
|
||||
|
||||
extern settings_t settings;
|
||||
|
||||
// Initialize the configuration subsystem (load settings from EEPROM)
|
||||
|
|
@ -149,5 +149,4 @@ uint8_t get_direction_pin_mask(uint8_t i);
|
|||
// Returns the limit pin mask according to Grbl's internal axis numbering
|
||||
uint8_t get_limit_pin_mask(uint8_t i);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,270 +21,273 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
||||
static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
||||
#endif
|
||||
|
||||
|
||||
void spindle_init()
|
||||
{
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
void spindle_init() {
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
|
||||
// combined unless configured otherwise.
|
||||
SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
|
||||
SPINDLE_PWM_DDR |= (1 << SPINDLE_PWM_BIT); // Configure as PWM output pin.
|
||||
SPINDLE_TCCRA_REGISTER = SPINDLE_TCCRA_INIT_MASK; // Configure PWM output compare timer
|
||||
SPINDLE_TCCRB_REGISTER = SPINDLE_TCCRB_INIT_MASK;
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
|
||||
#else
|
||||
#ifndef ENABLE_DUAL_AXIS
|
||||
SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
|
||||
#endif
|
||||
#endif
|
||||
pwm_gradient = SPINDLE_PWM_RANGE/(settings.rpm_max-settings.rpm_min);
|
||||
#else
|
||||
SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
|
||||
#ifndef ENABLE_DUAL_AXIS
|
||||
SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
SPINDLE_ENABLE_DDR |= (1 << SPINDLE_ENABLE_BIT); // Configure as output pin.
|
||||
#else
|
||||
#ifndef ENABLE_DUAL_AXIS
|
||||
SPINDLE_DIRECTION_DDR |= (1 << SPINDLE_DIRECTION_BIT); // Configure as output pin.
|
||||
#endif
|
||||
#endif
|
||||
pwm_gradient = SPINDLE_PWM_RANGE / (settings.rpm_max - settings.rpm_min);
|
||||
#else
|
||||
SPINDLE_ENABLE_DDR |= (1 << SPINDLE_ENABLE_BIT); // Configure as output pin.
|
||||
#ifndef ENABLE_DUAL_AXIS
|
||||
SPINDLE_DIRECTION_DDR |= (1 << SPINDLE_DIRECTION_BIT); // Configure as output pin.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
spindle_stop();
|
||||
spindle_stop();
|
||||
}
|
||||
|
||||
|
||||
uint8_t spindle_get_state()
|
||||
{
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
// No spindle direction output pin.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
if (bit_isfalse(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
|
||||
#else
|
||||
if (bit_istrue(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
|
||||
#endif
|
||||
#else
|
||||
if (SPINDLE_TCCRA_REGISTER & (1<<SPINDLE_COMB_BIT)) { // Check if PWM is enabled.
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
return(SPINDLE_STATE_CW);
|
||||
#else
|
||||
if (SPINDLE_DIRECTION_PORT & (1<<SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
|
||||
else { return(SPINDLE_STATE_CW); }
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
if (bit_isfalse(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(SPINDLE_ENABLE_PORT,(1<<SPINDLE_ENABLE_BIT))) {
|
||||
#endif
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
return(SPINDLE_STATE_CW);
|
||||
#else
|
||||
if (SPINDLE_DIRECTION_PORT & (1<<SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
|
||||
else { return(SPINDLE_STATE_CW); }
|
||||
#endif
|
||||
uint8_t spindle_get_state() {
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
// No spindle direction output pin.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
if (bit_isfalse(SPINDLE_ENABLE_PORT, (1 << SPINDLE_ENABLE_BIT))) {
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
#endif
|
||||
return(SPINDLE_STATE_DISABLE);
|
||||
#else
|
||||
if (bit_istrue(SPINDLE_ENABLE_PORT, (1 << SPINDLE_ENABLE_BIT))) {
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (SPINDLE_TCCRA_REGISTER & (1 << SPINDLE_COMB_BIT)) { // Check if PWM is enabled.
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
return (SPINDLE_STATE_CW);
|
||||
#else
|
||||
if (SPINDLE_DIRECTION_PORT & (1 << SPINDLE_DIRECTION_BIT)) {
|
||||
return (SPINDLE_STATE_CCW);
|
||||
} else {
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
if (bit_isfalse(SPINDLE_ENABLE_PORT, (1 << SPINDLE_ENABLE_BIT))) {
|
||||
#else
|
||||
if (bit_istrue(SPINDLE_ENABLE_PORT, (1 << SPINDLE_ENABLE_BIT))) {
|
||||
#endif
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
return (SPINDLE_STATE_CW);
|
||||
#else
|
||||
if (SPINDLE_DIRECTION_PORT & (1 << SPINDLE_DIRECTION_BIT)) {
|
||||
return (SPINDLE_STATE_CCW);
|
||||
} else {
|
||||
return (SPINDLE_STATE_CW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return (SPINDLE_STATE_DISABLE);
|
||||
}
|
||||
|
||||
|
||||
// Disables the spindle and sets PWM output to zero when PWM variable spindle speed is enabled.
|
||||
// Called by various main program and ISR routines. Keep routine small, fast, and efficient.
|
||||
// Called by spindle_init(), spindle_set_speed(), spindle_set_state(), and mc_reset().
|
||||
void spindle_stop()
|
||||
{
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); // Set pin to high
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); // Set pin to high
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
|
||||
#endif
|
||||
#endif
|
||||
void spindle_stop() {
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
SPINDLE_TCCRA_REGISTER &= ~(1 << SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
|
||||
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT |= (1 << SPINDLE_ENABLE_BIT); // Set pin to high
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT &= ~(1 << SPINDLE_ENABLE_BIT); // Set pin to low
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT |= (1 << SPINDLE_ENABLE_BIT); // Set pin to high
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT &= ~(1 << SPINDLE_ENABLE_BIT); // Set pin to low
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state()
|
||||
// and stepper ISR. Keep routine small and efficient.
|
||||
void spindle_set_speed(uint8_t pwm_value)
|
||||
{
|
||||
// Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state()
|
||||
// and stepper ISR. Keep routine small and efficient.
|
||||
void spindle_set_speed(uint8_t pwm_value) {
|
||||
SPINDLE_OCR_REGISTER = pwm_value; // Set PWM output level.
|
||||
#ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||
if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
|
||||
#ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||
if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
|
||||
spindle_stop();
|
||||
} else {
|
||||
SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
|
||||
SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
|
||||
} else {
|
||||
SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
SPINDLE_TCCRA_REGISTER |= (1 << SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT &= ~(1 << SPINDLE_ENABLE_BIT);
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT |= (1 << SPINDLE_ENABLE_BIT);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
|
||||
SPINDLE_TCCRA_REGISTER &= ~(1 << SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
|
||||
} else {
|
||||
SPINDLE_TCCRA_REGISTER |= (1 << SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
|
||||
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
|
||||
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
|
||||
uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
|
||||
{
|
||||
uint8_t pwm_value;
|
||||
rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= RPM_MAX)) {
|
||||
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
|
||||
uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
|
||||
{
|
||||
uint8_t pwm_value;
|
||||
rpm *= (0.010 * sys.spindle_speed_ovr); // Scale by spindle speed override value.
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= RPM_MAX)) {
|
||||
rpm = RPM_MAX;
|
||||
pwm_value = SPINDLE_PWM_MAX_VALUE;
|
||||
} else if (rpm <= RPM_MIN) {
|
||||
} else if (rpm <= RPM_MIN) {
|
||||
if (rpm == 0.0) { // S0 disables spindle
|
||||
pwm_value = SPINDLE_PWM_OFF_VALUE;
|
||||
pwm_value = SPINDLE_PWM_OFF_VALUE;
|
||||
} else {
|
||||
rpm = RPM_MIN;
|
||||
pwm_value = SPINDLE_PWM_MIN_VALUE;
|
||||
rpm = RPM_MIN;
|
||||
pwm_value = SPINDLE_PWM_MIN_VALUE;
|
||||
}
|
||||
} else {
|
||||
// Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
|
||||
#if (N_PIECES > 3)
|
||||
if (rpm > RPM_POINT34) {
|
||||
pwm_value = floor(RPM_LINE_A4*rpm - RPM_LINE_B4);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 2)
|
||||
if (rpm > RPM_POINT23) {
|
||||
pwm_value = floor(RPM_LINE_A3*rpm - RPM_LINE_B3);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 1)
|
||||
if (rpm > RPM_POINT12) {
|
||||
pwm_value = floor(RPM_LINE_A2*rpm - RPM_LINE_B2);
|
||||
} else
|
||||
#endif
|
||||
} else {
|
||||
// Compute intermediate PWM value with linear spindle speed model via piecewise linear fit model.
|
||||
#if (N_PIECES > 3)
|
||||
if (rpm > RPM_POINT34) {
|
||||
pwm_value = floor(RPM_LINE_A4 * rpm - RPM_LINE_B4);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 2)
|
||||
if (rpm > RPM_POINT23) {
|
||||
pwm_value = floor(RPM_LINE_A3 * rpm - RPM_LINE_B3);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 1)
|
||||
if (rpm > RPM_POINT12) {
|
||||
pwm_value = floor(RPM_LINE_A2 * rpm - RPM_LINE_B2);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
pwm_value = floor(RPM_LINE_A1*rpm - RPM_LINE_B1);
|
||||
pwm_value = floor(RPM_LINE_A1 * rpm - RPM_LINE_B1);
|
||||
}
|
||||
}
|
||||
sys.spindle_speed = rpm;
|
||||
return(pwm_value);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
|
||||
uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
|
||||
{
|
||||
uint8_t pwm_value;
|
||||
rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
|
||||
sys.spindle_speed = rpm;
|
||||
return (pwm_value);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
|
||||
uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
|
||||
{
|
||||
uint8_t pwm_value;
|
||||
rpm *= (0.010 * sys.spindle_speed_ovr); // Scale by spindle speed override value.
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
|
||||
// No PWM range possible. Set simple on/off spindle control pin state.
|
||||
sys.spindle_speed = settings.rpm_max;
|
||||
pwm_value = SPINDLE_PWM_MAX_VALUE;
|
||||
} else if (rpm <= settings.rpm_min) {
|
||||
} else if (rpm <= settings.rpm_min) {
|
||||
if (rpm == 0.0) { // S0 disables spindle
|
||||
sys.spindle_speed = 0.0;
|
||||
pwm_value = SPINDLE_PWM_OFF_VALUE;
|
||||
sys.spindle_speed = 0.0;
|
||||
pwm_value = SPINDLE_PWM_OFF_VALUE;
|
||||
} else { // Set minimum PWM output
|
||||
sys.spindle_speed = settings.rpm_min;
|
||||
pwm_value = SPINDLE_PWM_MIN_VALUE;
|
||||
sys.spindle_speed = settings.rpm_min;
|
||||
pwm_value = SPINDLE_PWM_MIN_VALUE;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
// Compute intermediate PWM value with linear spindle speed model.
|
||||
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
|
||||
sys.spindle_speed = rpm;
|
||||
pwm_value = floor((rpm-settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
|
||||
}
|
||||
return(pwm_value);
|
||||
pwm_value = floor((rpm - settings.rpm_min) * pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
return (pwm_value);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Immediately sets spindle running state with direction and spindle rpm via PWM, if enabled.
|
||||
// Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
|
||||
// sleep, and spindle stop override.
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
void spindle_set_state(uint8_t state, float rpm)
|
||||
void spindle_set_state(uint8_t state, float rpm)
|
||||
#else
|
||||
void _spindle_set_state(uint8_t state)
|
||||
void _spindle_set_state(uint8_t state)
|
||||
#endif
|
||||
{
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
if (sys.abort) {
|
||||
return;
|
||||
} // Block during abort.
|
||||
|
||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
sys.spindle_speed = 0.0;
|
||||
#endif
|
||||
spindle_stop();
|
||||
|
||||
} else {
|
||||
|
||||
#if !defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(ENABLE_DUAL_AXIS)
|
||||
if (state == SPINDLE_ENABLE_CW) {
|
||||
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
|
||||
} else {
|
||||
SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
|
||||
if (settings.flags & BITFLAG_LASER_MODE) {
|
||||
if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
|
||||
}
|
||||
spindle_set_speed(spindle_compute_pwm_value(rpm));
|
||||
#endif
|
||||
#if (defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && \
|
||||
!defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)) || !defined(VARIABLE_SPINDLE)
|
||||
// NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
|
||||
// if the spindle speed value is zero, as its ignored anyhow.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
sys.spindle_speed = 0.0;
|
||||
#endif
|
||||
spindle_stop();
|
||||
|
||||
} else {
|
||||
|
||||
#if !defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(ENABLE_DUAL_AXIS)
|
||||
if (state == SPINDLE_ENABLE_CW) {
|
||||
SPINDLE_DIRECTION_PORT &= ~(1 << SPINDLE_DIRECTION_BIT);
|
||||
} else {
|
||||
SPINDLE_DIRECTION_PORT |= (1 << SPINDLE_DIRECTION_BIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
|
||||
if (settings.flags & BITFLAG_LASER_MODE) {
|
||||
if (state == SPINDLE_ENABLE_CCW) {
|
||||
rpm = 0.0;
|
||||
} // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
|
||||
}
|
||||
spindle_set_speed(spindle_compute_pwm_value(rpm));
|
||||
#endif
|
||||
#if (defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && !defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)) || \
|
||||
!defined(VARIABLE_SPINDLE)
|
||||
// NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
|
||||
// if the spindle speed value is zero, as its ignored anyhow.
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
SPINDLE_ENABLE_PORT &= ~(1 << SPINDLE_ENABLE_BIT);
|
||||
#else
|
||||
SPINDLE_ENABLE_PORT |= (1 << SPINDLE_ENABLE_BIT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
|
||||
// G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails
|
||||
// G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails
|
||||
// if an abort or check-mode is active.
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
void spindle_sync(uint8_t state, float rpm)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
void spindle_sync(uint8_t state, float rpm) {
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
||||
spindle_set_state(state,rpm);
|
||||
}
|
||||
spindle_set_state(state, rpm);
|
||||
}
|
||||
#else
|
||||
void _spindle_sync(uint8_t state)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
void _spindle_sync(uint8_t state) {
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
||||
_spindle_set_state(state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,13 +22,12 @@
|
|||
#ifndef spindle_control_h
|
||||
#define spindle_control_h
|
||||
|
||||
#define SPINDLE_NO_SYNC false
|
||||
#define SPINDLE_NO_SYNC false
|
||||
#define SPINDLE_FORCE_SYNC true
|
||||
|
||||
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
||||
#define SPINDLE_STATE_CW bit(0)
|
||||
#define SPINDLE_STATE_CCW bit(1)
|
||||
|
||||
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
||||
#define SPINDLE_STATE_CW bit(0)
|
||||
#define SPINDLE_STATE_CCW bit(1)
|
||||
|
||||
// Initializes spindle pins and hardware PWM, if enabled.
|
||||
void spindle_init();
|
||||
|
|
@ -41,33 +40,32 @@ uint8_t spindle_get_state();
|
|||
// Called by spindle_sync() after sync and parking motion/spindle stop override during restore.
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
|
||||
// Called by g-code parser when setting spindle state and requires a buffer sync.
|
||||
void spindle_sync(uint8_t state, float rpm);
|
||||
// Called by g-code parser when setting spindle state and requires a buffer sync.
|
||||
void spindle_sync(uint8_t state, float rpm);
|
||||
|
||||
// Sets spindle running state with direction, enable, and spindle PWM.
|
||||
void spindle_set_state(uint8_t state, float rpm);
|
||||
|
||||
// Sets spindle PWM quickly for stepper ISR. Also called by spindle_set_state().
|
||||
// NOTE: 328p PWM register is 8-bit.
|
||||
void spindle_set_speed(uint8_t pwm_value);
|
||||
|
||||
// Computes 328p-specific PWM register value for the given RPM for quick updating.
|
||||
uint8_t spindle_compute_pwm_value(float rpm);
|
||||
|
||||
// Sets spindle running state with direction, enable, and spindle PWM.
|
||||
void spindle_set_state(uint8_t state, float rpm);
|
||||
|
||||
// Sets spindle PWM quickly for stepper ISR. Also called by spindle_set_state().
|
||||
// NOTE: 328p PWM register is 8-bit.
|
||||
void spindle_set_speed(uint8_t pwm_value);
|
||||
|
||||
// Computes 328p-specific PWM register value for the given RPM for quick updating.
|
||||
uint8_t spindle_compute_pwm_value(float rpm);
|
||||
|
||||
#else
|
||||
|
||||
// Called by g-code parser when setting spindle state and requires a buffer sync.
|
||||
#define spindle_sync(state, rpm) _spindle_sync(state)
|
||||
void _spindle_sync(uint8_t state);
|
||||
|
||||
// Sets spindle running state with direction and enable.
|
||||
#define spindle_set_state(state, rpm) _spindle_set_state(state)
|
||||
void _spindle_set_state(uint8_t state);
|
||||
// Called by g-code parser when setting spindle state and requires a buffer sync.
|
||||
#define spindle_sync(state, rpm) _spindle_sync(state)
|
||||
void _spindle_sync(uint8_t state);
|
||||
|
||||
// Sets spindle running state with direction and enable.
|
||||
#define spindle_set_state(state, rpm) _spindle_set_state(state)
|
||||
void _spindle_set_state(uint8_t state);
|
||||
|
||||
#endif
|
||||
|
||||
// Stop and start spindle routines. Called by all spindle routines and stepper ISR.
|
||||
void spindle_stop();
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
1606
grbl/stepper.c
1606
grbl/stepper.c
File diff suppressed because it is too large
Load diff
|
|
@ -23,7 +23,7 @@
|
|||
#define stepper_h
|
||||
|
||||
#ifndef SEGMENT_BUFFER_SIZE
|
||||
#define SEGMENT_BUFFER_SIZE 6
|
||||
#define SEGMENT_BUFFER_SIZE 6
|
||||
#endif
|
||||
|
||||
// Initialize and setup the stepper motor subsystem
|
||||
|
|
|
|||
651
grbl/system.c
651
grbl/system.c
|
|
@ -20,98 +20,95 @@
|
|||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
void system_init()
|
||||
{
|
||||
CONTROL_DDR &= ~(CONTROL_MASK); // Configure as input pins
|
||||
#ifdef DISABLE_CONTROL_PIN_PULL_UP
|
||||
void system_init() {
|
||||
CONTROL_DDR &= ~(CONTROL_MASK); // Configure as input pins
|
||||
#ifdef DISABLE_CONTROL_PIN_PULL_UP
|
||||
CONTROL_PORT &= ~(CONTROL_MASK); // Normal low operation. Requires external pull-down.
|
||||
#else
|
||||
CONTROL_PORT |= CONTROL_MASK; // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
CONTROL_PCMSK |= CONTROL_MASK; // Enable specific pins of the Pin Change Interrupt
|
||||
PCICR |= (1 << CONTROL_INT); // Enable Pin Change Interrupt
|
||||
#else
|
||||
CONTROL_PORT |= CONTROL_MASK; // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
CONTROL_PCMSK |= CONTROL_MASK; // Enable specific pins of the Pin Change Interrupt
|
||||
PCICR |= (1 << CONTROL_INT); // Enable Pin Change Interrupt
|
||||
}
|
||||
|
||||
|
||||
// Returns control pin state as a uint8 bitfield. Each bit indicates the input pin state, where
|
||||
// triggered is 1 and not triggered is 0. Invert mask is applied. Bitfield organization is
|
||||
// defined by the CONTROL_PIN_INDEX in the header file.
|
||||
uint8_t system_control_get_state()
|
||||
{
|
||||
uint8_t control_state = 0;
|
||||
uint8_t pin = (CONTROL_PIN & CONTROL_MASK) ^ CONTROL_MASK;
|
||||
#ifdef INVERT_CONTROL_PIN_MASK
|
||||
uint8_t system_control_get_state() {
|
||||
uint8_t control_state = 0;
|
||||
uint8_t pin = (CONTROL_PIN & CONTROL_MASK) ^ CONTROL_MASK;
|
||||
#ifdef INVERT_CONTROL_PIN_MASK
|
||||
pin ^= INVERT_CONTROL_PIN_MASK;
|
||||
#endif
|
||||
if (pin) {
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
if (bit_istrue(pin,(1<<CONTROL_SAFETY_DOOR_BIT))) { control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR; }
|
||||
#else
|
||||
if (bit_istrue(pin,(1<<CONTROL_FEED_HOLD_BIT))) { control_state |= CONTROL_PIN_INDEX_FEED_HOLD; }
|
||||
#endif
|
||||
if (bit_istrue(pin,(1<<CONTROL_RESET_BIT))) { control_state |= CONTROL_PIN_INDEX_RESET; }
|
||||
if (bit_istrue(pin,(1<<CONTROL_CYCLE_START_BIT))) { control_state |= CONTROL_PIN_INDEX_CYCLE_START; }
|
||||
}
|
||||
return(control_state);
|
||||
#endif
|
||||
if (pin) {
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
if (bit_istrue(pin, (1 << CONTROL_SAFETY_DOOR_BIT))) {
|
||||
control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR;
|
||||
}
|
||||
#else
|
||||
if (bit_istrue(pin, (1 << CONTROL_FEED_HOLD_BIT))) {
|
||||
control_state |= CONTROL_PIN_INDEX_FEED_HOLD;
|
||||
}
|
||||
#endif
|
||||
if (bit_istrue(pin, (1 << CONTROL_RESET_BIT))) {
|
||||
control_state |= CONTROL_PIN_INDEX_RESET;
|
||||
}
|
||||
if (bit_istrue(pin, (1 << CONTROL_CYCLE_START_BIT))) {
|
||||
control_state |= CONTROL_PIN_INDEX_CYCLE_START;
|
||||
}
|
||||
}
|
||||
return (control_state);
|
||||
}
|
||||
|
||||
|
||||
// Pin change interrupt for pin-out commands, i.e. cycle start, feed hold, and reset. Sets
|
||||
// only the realtime command execute variable to have the main program execute these when
|
||||
// its ready. This works exactly like the character-based realtime commands when picked off
|
||||
// directly from the incoming serial data stream.
|
||||
ISR(CONTROL_INT_vect)
|
||||
{
|
||||
uint8_t pin = system_control_get_state();
|
||||
if (pin) {
|
||||
if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET)) {
|
||||
mc_reset();
|
||||
ISR(CONTROL_INT_vect) {
|
||||
uint8_t pin = system_control_get_state();
|
||||
if (pin) {
|
||||
if (bit_istrue(pin, CONTROL_PIN_INDEX_RESET)) {
|
||||
mc_reset();
|
||||
}
|
||||
if (bit_istrue(pin, CONTROL_PIN_INDEX_CYCLE_START)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
|
||||
}
|
||||
#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
if (bit_istrue(pin, CONTROL_PIN_INDEX_FEED_HOLD)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);
|
||||
#else
|
||||
if (bit_istrue(pin, CONTROL_PIN_INDEX_SAFETY_DOOR)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
|
||||
}
|
||||
#ifndef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);
|
||||
#else
|
||||
if (bit_istrue(pin,CONTROL_PIN_INDEX_SAFETY_DOOR)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns if safety door is ajar(T) or closed(F), based on pin state.
|
||||
uint8_t system_check_safety_door_ajar()
|
||||
{
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
return(system_control_get_state() & CONTROL_PIN_INDEX_SAFETY_DOOR);
|
||||
#else
|
||||
return(false); // Input pin not enabled, so just return that it's closed.
|
||||
#endif
|
||||
uint8_t system_check_safety_door_ajar() {
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
return (system_control_get_state() & CONTROL_PIN_INDEX_SAFETY_DOOR);
|
||||
#else
|
||||
return (false); // Input pin not enabled, so just return that it's closed.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Executes user startup script, if stored.
|
||||
void system_execute_startup(char *line)
|
||||
{
|
||||
uint8_t n;
|
||||
for (n=0; n < N_STARTUP_LINE; n++) {
|
||||
if (!(settings_read_startup_line(n, line))) {
|
||||
line[0] = 0;
|
||||
report_execute_startup_message(line,STATUS_SETTING_READ_FAIL);
|
||||
} else {
|
||||
if (line[0] != 0) {
|
||||
uint8_t status_code = gc_execute_line(line);
|
||||
report_execute_startup_message(line,status_code);
|
||||
}
|
||||
void system_execute_startup(char *line) {
|
||||
uint8_t n;
|
||||
for (n = 0; n < N_STARTUP_LINE; n++) {
|
||||
if (!(settings_read_startup_line(n, line))) {
|
||||
line[0] = 0;
|
||||
report_execute_startup_message(line, STATUS_SETTING_READ_FAIL);
|
||||
} else {
|
||||
if (line[0] != 0) {
|
||||
uint8_t status_code = gc_execute_line(line);
|
||||
report_execute_startup_message(line, status_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Directs and executes one line of formatted input from protocol_process. While mostly
|
||||
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
|
||||
// settings, initiating the homing cycle, and toggling switch states. This differs from
|
||||
|
|
@ -120,291 +117,331 @@ void system_execute_startup(char *line)
|
|||
// the lines that are processed afterward, not necessarily real-time during a cycle,
|
||||
// since there are motions already stored in the buffer. However, this 'lag' should not
|
||||
// be an issue, since these commands are not typically used during a cycle.
|
||||
uint8_t system_execute_line(char *line)
|
||||
{
|
||||
uint8_t char_counter = 1;
|
||||
uint8_t helper_var = 0; // Helper variable
|
||||
float parameter, value;
|
||||
switch( line[char_counter] ) {
|
||||
case 0 : report_grbl_help(); break;
|
||||
case 'J' : // Jogging
|
||||
// Execute only if in IDLE or JOG states.
|
||||
if (sys.state != STATE_IDLE && sys.state != STATE_JOG) { return(STATUS_IDLE_ERROR); }
|
||||
if(line[2] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
return(gc_execute_line(line)); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
|
||||
break;
|
||||
case '$': case 'G': case 'C': case 'X':
|
||||
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
|
||||
switch( line[1] ) {
|
||||
case '$' : // Prints Grbl settings
|
||||
if ( sys.state & (STATE_CYCLE | STATE_HOLD) ) { return(STATUS_IDLE_ERROR); } // Block during cycle. Takes too long to print.
|
||||
else { report_grbl_settings(); }
|
||||
break;
|
||||
case 'G' : // Prints gcode parser state
|
||||
// TODO: Move this to realtime commands for GUIs to request this data during suspend-state.
|
||||
report_gcode_modes();
|
||||
break;
|
||||
case 'C' : // Set check g-code mode [IDLE/CHECK]
|
||||
// Perform reset when toggling off. Check g-code mode should only work if Grbl
|
||||
// is idle and ready, regardless of alarm locks. This is mainly to keep things
|
||||
// simple and consistent.
|
||||
if ( sys.state == STATE_CHECK_MODE ) {
|
||||
mc_reset();
|
||||
report_feedback_message(MESSAGE_DISABLED);
|
||||
} else {
|
||||
if (sys.state) { return(STATUS_IDLE_ERROR); } // Requires no alarm mode.
|
||||
sys.state = STATE_CHECK_MODE;
|
||||
report_feedback_message(MESSAGE_ENABLED);
|
||||
}
|
||||
break;
|
||||
case 'X' : // Disable alarm lock [ALARM]
|
||||
if (sys.state == STATE_ALARM) {
|
||||
// Block if safety door is ajar.
|
||||
if (system_check_safety_door_ajar()) { return(STATUS_CHECK_DOOR); }
|
||||
report_feedback_message(MESSAGE_ALARM_UNLOCK);
|
||||
sys.state = STATE_IDLE;
|
||||
// Don't run startup script. Prevents stored moves in startup from causing accidents.
|
||||
} // Otherwise, no effect.
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
|
||||
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
|
||||
switch( line[1] ) {
|
||||
case '#' : // Print Grbl NGC parameters
|
||||
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
|
||||
else { report_ngc_parameters(); }
|
||||
break;
|
||||
case 'H' : // Perform homing cycle [IDLE/ALARM]
|
||||
if (bit_isfalse(settings.flags,BITFLAG_HOMING_ENABLE)) {return(STATUS_SETTING_DISABLED); }
|
||||
if (system_check_safety_door_ajar()) { return(STATUS_CHECK_DOOR); } // Block if safety door is ajar.
|
||||
sys.state = STATE_HOMING; // Set system state variable
|
||||
if (line[2] == 0) {
|
||||
mc_homing_cycle(HOMING_CYCLE_ALL);
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
uint8_t system_execute_line(char *line) {
|
||||
uint8_t char_counter = 1;
|
||||
uint8_t helper_var = 0; // Helper variable
|
||||
float parameter, value;
|
||||
switch (line[char_counter]) {
|
||||
case 0: report_grbl_help(); break;
|
||||
case 'J': // Jogging
|
||||
// Execute only if in IDLE or JOG states.
|
||||
if (sys.state != STATE_IDLE && sys.state != STATE_JOG) {
|
||||
return (STATUS_IDLE_ERROR);
|
||||
}
|
||||
if (line[2] != '=') {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
return (gc_execute_line(line)); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
|
||||
break;
|
||||
case '$':
|
||||
case 'G':
|
||||
case 'C':
|
||||
case 'X':
|
||||
if (line[2] != 0) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
switch (line[1]) {
|
||||
case '$': // Prints Grbl settings
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOLD)) {
|
||||
return (STATUS_IDLE_ERROR);
|
||||
} // Block during cycle. Takes too long to print.
|
||||
else {
|
||||
report_grbl_settings();
|
||||
}
|
||||
break;
|
||||
case 'G': // Prints gcode parser state
|
||||
// TODO: Move this to realtime commands for GUIs to request this data during suspend-state.
|
||||
report_gcode_modes();
|
||||
break;
|
||||
case 'C': // Set check g-code mode [IDLE/CHECK]
|
||||
// Perform reset when toggling off. Check g-code mode should only work if Grbl
|
||||
// is idle and ready, regardless of alarm locks. This is mainly to keep things
|
||||
// simple and consistent.
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
mc_reset();
|
||||
report_feedback_message(MESSAGE_DISABLED);
|
||||
} else {
|
||||
if (sys.state) {
|
||||
return (STATUS_IDLE_ERROR);
|
||||
} // Requires no alarm mode.
|
||||
sys.state = STATE_CHECK_MODE;
|
||||
report_feedback_message(MESSAGE_ENABLED);
|
||||
}
|
||||
break;
|
||||
case 'X': // Disable alarm lock [ALARM]
|
||||
if (sys.state == STATE_ALARM) {
|
||||
// Block if safety door is ajar.
|
||||
if (system_check_safety_door_ajar()) {
|
||||
return (STATUS_CHECK_DOOR);
|
||||
}
|
||||
report_feedback_message(MESSAGE_ALARM_UNLOCK);
|
||||
sys.state = STATE_IDLE;
|
||||
// Don't run startup script. Prevents stored moves in startup from causing accidents.
|
||||
} // Otherwise, no effect.
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
|
||||
if (!(sys.state == STATE_IDLE || sys.state == STATE_ALARM)) {
|
||||
return (STATUS_IDLE_ERROR);
|
||||
}
|
||||
switch (line[1]) {
|
||||
case '#': // Print Grbl NGC parameters
|
||||
if (line[2] != 0) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
} else {
|
||||
report_ngc_parameters();
|
||||
}
|
||||
break;
|
||||
case 'H': // Perform homing cycle [IDLE/ALARM]
|
||||
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) {
|
||||
return (STATUS_SETTING_DISABLED);
|
||||
}
|
||||
if (system_check_safety_door_ajar()) {
|
||||
return (STATUS_CHECK_DOOR);
|
||||
} // Block if safety door is ajar.
|
||||
sys.state = STATE_HOMING; // Set system state variable
|
||||
if (line[2] == 0) {
|
||||
mc_homing_cycle(HOMING_CYCLE_ALL);
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
} else if (line[3] == 0) {
|
||||
switch (line[2]) {
|
||||
switch (line[2]) {
|
||||
case 'X': mc_homing_cycle(HOMING_CYCLE_X); break;
|
||||
case 'Y': mc_homing_cycle(HOMING_CYCLE_Y); break;
|
||||
case 'Z': mc_homing_cycle(HOMING_CYCLE_Z); break;
|
||||
default: return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
#endif
|
||||
} else { return(STATUS_INVALID_STATEMENT); }
|
||||
if (!sys.abort) { // Execute startup scripts after successful homing.
|
||||
sys.state = STATE_IDLE; // Set to IDLE when complete.
|
||||
st_go_idle(); // Set steppers to the settings idle state before returning.
|
||||
if (line[2] == 0) { system_execute_startup(line); }
|
||||
}
|
||||
break;
|
||||
case 'S' : // Puts Grbl to sleep [IDLE/ALARM]
|
||||
if ((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0)) { return(STATUS_INVALID_STATEMENT); }
|
||||
system_set_exec_state_flag(EXEC_SLEEP); // Set to execute sleep mode immediately
|
||||
break;
|
||||
case 'I' : // Print or store build info. [IDLE/ALARM]
|
||||
if ( line[++char_counter] == 0 ) {
|
||||
settings_read_build_info(line);
|
||||
report_build_info(line);
|
||||
#ifdef ENABLE_BUILD_INFO_WRITE_COMMAND
|
||||
} else { // Store startup line [IDLE/ALARM]
|
||||
if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
helper_var = char_counter; // Set helper variable as counter to start of user info line.
|
||||
do {
|
||||
line[char_counter-helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
settings_store_build_info(line);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 'R' : // Restore defaults [IDLE/ALARM]
|
||||
if ((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0)) { return(STATUS_INVALID_STATEMENT); }
|
||||
switch (line[5]) {
|
||||
#ifdef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS
|
||||
case '$': settings_restore(SETTINGS_RESTORE_DEFAULTS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS
|
||||
case '#': settings_restore(SETTINGS_RESTORE_PARAMETERS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_WIPE_ALL
|
||||
case '*': settings_restore(SETTINGS_RESTORE_ALL); break;
|
||||
#endif
|
||||
default: return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
report_feedback_message(MESSAGE_RESTORE_DEFAULTS);
|
||||
mc_reset(); // Force reset to ensure settings are initialized correctly.
|
||||
break;
|
||||
case 'N' : // Startup lines. [IDLE/ALARM]
|
||||
if ( line[++char_counter] == 0 ) { // Print startup lines
|
||||
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
|
||||
if (!(settings_read_startup_line(helper_var, line))) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL);
|
||||
} else {
|
||||
report_startup_line(helper_var,line);
|
||||
}
|
||||
default: return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
if (!sys.abort) { // Execute startup scripts after successful homing.
|
||||
sys.state = STATE_IDLE; // Set to IDLE when complete.
|
||||
st_go_idle(); // Set steppers to the settings idle state before returning.
|
||||
if (line[2] == 0) {
|
||||
system_execute_startup(line);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else { // Store startup line [IDLE Only] Prevents motion during ALARM.
|
||||
if (sys.state != STATE_IDLE) { return(STATUS_IDLE_ERROR); } // Store only when idle.
|
||||
helper_var = true; // Set helper_var to flag storing method.
|
||||
// No break. Continues into default: to read remaining command characters.
|
||||
}
|
||||
default : // Storing setting methods [IDLE/ALARM]
|
||||
if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); }
|
||||
if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
if (helper_var) { // Store startup line
|
||||
// Prepare sending gcode block to gcode parser by shifting all characters
|
||||
helper_var = char_counter; // Set helper variable as counter to start of gcode block
|
||||
do {
|
||||
line[char_counter-helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
// Execute gcode block to ensure block is valid.
|
||||
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
|
||||
if (helper_var) { return(helper_var); }
|
||||
else {
|
||||
helper_var = trunc(parameter); // Set helper_var to int value of parameter
|
||||
settings_store_startup_line(helper_var,line);
|
||||
case 'S': // Puts Grbl to sleep [IDLE/ALARM]
|
||||
if ((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0)) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
} else { // Store global setting.
|
||||
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
|
||||
if((line[char_counter] != 0) || (parameter > 255)) { return(STATUS_INVALID_STATEMENT); }
|
||||
return(settings_store_global_setting((uint8_t)parameter, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
|
||||
system_set_exec_state_flag(EXEC_SLEEP); // Set to execute sleep mode immediately
|
||||
break;
|
||||
case 'I': // Print or store build info. [IDLE/ALARM]
|
||||
if (line[++char_counter] == 0) {
|
||||
settings_read_build_info(line);
|
||||
report_build_info(line);
|
||||
#ifdef ENABLE_BUILD_INFO_WRITE_COMMAND
|
||||
} else { // Store startup line [IDLE/ALARM]
|
||||
if (line[char_counter++] != '=') {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
helper_var = char_counter; // Set helper variable as counter to start of user info line.
|
||||
do {
|
||||
line[char_counter - helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
settings_store_build_info(line);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 'R': // Restore defaults [IDLE/ALARM]
|
||||
if ((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0)) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
switch (line[5]) {
|
||||
#ifdef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS
|
||||
case '$': settings_restore(SETTINGS_RESTORE_DEFAULTS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS
|
||||
case '#': settings_restore(SETTINGS_RESTORE_PARAMETERS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_WIPE_ALL
|
||||
case '*': settings_restore(SETTINGS_RESTORE_ALL); break;
|
||||
#endif
|
||||
default: return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
report_feedback_message(MESSAGE_RESTORE_DEFAULTS);
|
||||
mc_reset(); // Force reset to ensure settings are initialized correctly.
|
||||
break;
|
||||
case 'N': // Startup lines. [IDLE/ALARM]
|
||||
if (line[++char_counter] == 0) { // Print startup lines
|
||||
for (helper_var = 0; helper_var < N_STARTUP_LINE; helper_var++) {
|
||||
if (!(settings_read_startup_line(helper_var, line))) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL);
|
||||
} else {
|
||||
report_startup_line(helper_var, line);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else { // Store startup line [IDLE Only] Prevents motion during ALARM.
|
||||
if (sys.state != STATE_IDLE) {
|
||||
return (STATUS_IDLE_ERROR);
|
||||
} // Store only when idle.
|
||||
helper_var = true; // Set helper_var to flag storing method.
|
||||
// No break. Continues into default: to read remaining command characters.
|
||||
}
|
||||
default: // Storing setting methods [IDLE/ALARM]
|
||||
if (!read_float(line, &char_counter, ¶meter)) {
|
||||
return (STATUS_BAD_NUMBER_FORMAT);
|
||||
}
|
||||
if (line[char_counter++] != '=') {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
if (helper_var) { // Store startup line
|
||||
// Prepare sending gcode block to gcode parser by shifting all characters
|
||||
helper_var = char_counter; // Set helper variable as counter to start of gcode block
|
||||
do {
|
||||
line[char_counter - helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
// Execute gcode block to ensure block is valid.
|
||||
helper_var = gc_execute_line(line); // Set helper_var to returned status code.
|
||||
if (helper_var) {
|
||||
return (helper_var);
|
||||
} else {
|
||||
helper_var = trunc(parameter); // Set helper_var to int value of parameter
|
||||
settings_store_startup_line(helper_var, line);
|
||||
}
|
||||
} else { // Store global setting.
|
||||
if (!read_float(line, &char_counter, &value)) {
|
||||
return (STATUS_BAD_NUMBER_FORMAT);
|
||||
}
|
||||
if ((line[char_counter] != 0) || (parameter > 255)) {
|
||||
return (STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
return (settings_store_global_setting((uint8_t)parameter, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return (STATUS_OK); // If '$' command makes it to here, then everything's ok.
|
||||
}
|
||||
|
||||
|
||||
|
||||
void system_flag_wco_change()
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE
|
||||
void system_flag_wco_change() {
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE
|
||||
protocol_buffer_synchronize();
|
||||
#endif
|
||||
sys.report_wco_counter = 0;
|
||||
#endif
|
||||
sys.report_wco_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
|
||||
// NOTE: If motor steps and machine position are not in the same coordinate frame, this function
|
||||
// serves as a central place to compute the transformation.
|
||||
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx)
|
||||
{
|
||||
float pos;
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
} else if (idx==Y_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx) {
|
||||
float pos;
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
} else if (idx == Y_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
} else {
|
||||
pos = steps[idx]/settings.steps_per_mm[idx];
|
||||
pos = steps[idx] / settings.steps_per_mm[idx];
|
||||
}
|
||||
#else
|
||||
pos = steps[idx]/settings.steps_per_mm[idx];
|
||||
#endif
|
||||
return(pos);
|
||||
#else
|
||||
pos = steps[idx] / settings.steps_per_mm[idx];
|
||||
#endif
|
||||
return (pos);
|
||||
}
|
||||
|
||||
|
||||
void system_convert_array_steps_to_mpos(float *position, int32_t *steps)
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
position[idx] = system_convert_axis_steps_to_mpos(steps, idx);
|
||||
}
|
||||
return;
|
||||
void system_convert_array_steps_to_mpos(float *position, int32_t *steps) {
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
position[idx] = system_convert_axis_steps_to_mpos(steps, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps.
|
||||
#ifdef COREXY
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps)
|
||||
{
|
||||
return( (steps[A_MOTOR] + steps[B_MOTOR])/2 );
|
||||
}
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps)
|
||||
{
|
||||
return( (steps[A_MOTOR] - steps[B_MOTOR])/2 );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Checks and reports if target array exceeds machine travel limits.
|
||||
uint8_t system_check_travel_limits(float *target)
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
// When homing forced set origin is enabled, soft limits checks need to account for directionality.
|
||||
// NOTE: max_travel is stored as negative
|
||||
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
|
||||
if (target[idx] < 0 || target[idx] > -settings.max_travel[idx]) { return(true); }
|
||||
} else {
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { return(true); }
|
||||
}
|
||||
#else
|
||||
// NOTE: max_travel is stored as negative
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { return(true); }
|
||||
#endif
|
||||
}
|
||||
return(false);
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps) {
|
||||
return ((steps[A_MOTOR] + steps[B_MOTOR]) / 2);
|
||||
}
|
||||
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps) {
|
||||
return ((steps[A_MOTOR] - steps[B_MOTOR]) / 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Checks and reports if target array exceeds machine travel limits.
|
||||
uint8_t system_check_travel_limits(float *target) {
|
||||
uint8_t idx;
|
||||
for (idx = 0; idx < N_AXIS; idx++) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
// When homing forced set origin is enabled, soft limits checks need to account for directionality.
|
||||
// NOTE: max_travel is stored as negative
|
||||
if (bit_istrue(settings.homing_dir_mask, bit(idx))) {
|
||||
if (target[idx] < 0 || target[idx] > -settings.max_travel[idx]) {
|
||||
return (true);
|
||||
}
|
||||
} else {
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// NOTE: max_travel is stored as negative
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) {
|
||||
return (true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
// Special handlers for setting and clearing Grbl's real-time execution flags.
|
||||
void system_set_exec_state_flag(uint8_t mask) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_state |= (mask);
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_state |= (mask);
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_state_flag(uint8_t mask) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_state &= ~(mask);
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_state &= ~(mask);
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_alarm(uint8_t code) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_alarm = code;
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_alarm = code;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_alarm() {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_alarm = 0;
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_alarm = 0;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_motion_override_flag(uint8_t mask) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_motion_override |= (mask);
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_motion_override |= (mask);
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_accessory_override_flag(uint8_t mask) {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_accessory_override |= (mask);
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_accessory_override |= (mask);
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_motion_overrides() {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_motion_override = 0;
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_motion_override = 0;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_accessory_overrides() {
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
SREG = sreg;
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
SREG = sreg;
|
||||
}
|
||||
|
|
|
|||
209
grbl/system.h
209
grbl/system.h
|
|
@ -28,141 +28,144 @@
|
|||
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
|
||||
// flags are always false, so the realtime protocol only needs to check for a non-zero value to
|
||||
// know when there is a realtime command to execute.
|
||||
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
|
||||
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
|
||||
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
|
||||
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
|
||||
#define EXEC_RESET bit(4) // bitmask 00010000
|
||||
#define EXEC_SAFETY_DOOR bit(5) // bitmask 00100000
|
||||
#define EXEC_MOTION_CANCEL bit(6) // bitmask 01000000
|
||||
#define EXEC_SLEEP bit(7) // bitmask 10000000
|
||||
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
|
||||
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
|
||||
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
|
||||
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
|
||||
#define EXEC_RESET bit(4) // bitmask 00010000
|
||||
#define EXEC_SAFETY_DOOR bit(5) // bitmask 00100000
|
||||
#define EXEC_MOTION_CANCEL bit(6) // bitmask 01000000
|
||||
#define EXEC_SLEEP bit(7) // bitmask 10000000
|
||||
|
||||
// Alarm executor codes. Valid values (1-255). Zero is reserved.
|
||||
#define EXEC_ALARM_HARD_LIMIT 1
|
||||
#define EXEC_ALARM_SOFT_LIMIT 2
|
||||
#define EXEC_ALARM_ABORT_CYCLE 3
|
||||
#define EXEC_ALARM_PROBE_FAIL_INITIAL 4
|
||||
#define EXEC_ALARM_PROBE_FAIL_CONTACT 5
|
||||
#define EXEC_ALARM_HOMING_FAIL_RESET 6
|
||||
#define EXEC_ALARM_HOMING_FAIL_DOOR 7
|
||||
#define EXEC_ALARM_HOMING_FAIL_PULLOFF 8
|
||||
#define EXEC_ALARM_HOMING_FAIL_APPROACH 9
|
||||
#define EXEC_ALARM_HOMING_FAIL_DUAL_APPROACH 10
|
||||
#define EXEC_ALARM_HARD_LIMIT 1
|
||||
#define EXEC_ALARM_SOFT_LIMIT 2
|
||||
#define EXEC_ALARM_ABORT_CYCLE 3
|
||||
#define EXEC_ALARM_PROBE_FAIL_INITIAL 4
|
||||
#define EXEC_ALARM_PROBE_FAIL_CONTACT 5
|
||||
#define EXEC_ALARM_HOMING_FAIL_RESET 6
|
||||
#define EXEC_ALARM_HOMING_FAIL_DOOR 7
|
||||
#define EXEC_ALARM_HOMING_FAIL_PULLOFF 8
|
||||
#define EXEC_ALARM_HOMING_FAIL_APPROACH 9
|
||||
#define EXEC_ALARM_HOMING_FAIL_DUAL_APPROACH 10
|
||||
|
||||
// Override bit maps. Realtime bitflags to control feed, rapid, spindle, and coolant overrides.
|
||||
// Spindle/coolant and feed/rapids are separated into two controlling flag variables.
|
||||
#define EXEC_FEED_OVR_RESET bit(0)
|
||||
#define EXEC_FEED_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_FEED_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_FEED_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_FEED_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_RAPID_OVR_RESET bit(5)
|
||||
#define EXEC_RAPID_OVR_MEDIUM bit(6)
|
||||
#define EXEC_RAPID_OVR_LOW bit(7)
|
||||
#define EXEC_FEED_OVR_RESET bit(0)
|
||||
#define EXEC_FEED_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_FEED_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_FEED_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_FEED_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_RAPID_OVR_RESET bit(5)
|
||||
#define EXEC_RAPID_OVR_MEDIUM bit(6)
|
||||
#define EXEC_RAPID_OVR_LOW bit(7)
|
||||
// #define EXEC_RAPID_OVR_EXTRA_LOW bit(*) // *NOT SUPPORTED*
|
||||
|
||||
#define EXEC_SPINDLE_OVR_RESET bit(0)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_SPINDLE_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_SPINDLE_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_SPINDLE_OVR_STOP bit(5)
|
||||
#define EXEC_COOLANT_FLOOD_OVR_TOGGLE bit(6)
|
||||
#define EXEC_COOLANT_MIST_OVR_TOGGLE bit(7)
|
||||
#define EXEC_SPINDLE_OVR_RESET bit(0)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_SPINDLE_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_SPINDLE_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_SPINDLE_OVR_STOP bit(5)
|
||||
#define EXEC_COOLANT_FLOOD_OVR_TOGGLE bit(6)
|
||||
#define EXEC_COOLANT_MIST_OVR_TOGGLE bit(7)
|
||||
|
||||
// Define system state bit map. The state variable primarily tracks the individual functions
|
||||
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
|
||||
// critical events.
|
||||
#define STATE_IDLE 0 // Must be zero. No flags.
|
||||
#define STATE_ALARM bit(0) // In alarm state. Locks out all g-code processes. Allows settings access.
|
||||
#define STATE_CHECK_MODE bit(1) // G-code check mode. Locks out planner and motion only.
|
||||
#define STATE_HOMING bit(2) // Performing homing cycle
|
||||
#define STATE_CYCLE bit(3) // Cycle is running or motions are being executed.
|
||||
#define STATE_HOLD bit(4) // Active feed hold
|
||||
#define STATE_JOG bit(5) // Jogging mode.
|
||||
#define STATE_SAFETY_DOOR bit(6) // Safety door is ajar. Feed holds and de-energizes system.
|
||||
#define STATE_SLEEP bit(7) // Sleep state.
|
||||
#define STATE_IDLE 0 // Must be zero. No flags.
|
||||
#define STATE_ALARM bit(0) // In alarm state. Locks out all g-code processes. Allows settings access.
|
||||
#define STATE_CHECK_MODE bit(1) // G-code check mode. Locks out planner and motion only.
|
||||
#define STATE_HOMING bit(2) // Performing homing cycle
|
||||
#define STATE_CYCLE bit(3) // Cycle is running or motions are being executed.
|
||||
#define STATE_HOLD bit(4) // Active feed hold
|
||||
#define STATE_JOG bit(5) // Jogging mode.
|
||||
#define STATE_SAFETY_DOOR bit(6) // Safety door is ajar. Feed holds and de-energizes system.
|
||||
#define STATE_SLEEP bit(7) // Sleep state.
|
||||
|
||||
// Define system suspend flags. Used in various ways to manage suspend states and procedures.
|
||||
#define SUSPEND_DISABLE 0 // Must be zero.
|
||||
#define SUSPEND_HOLD_COMPLETE bit(0) // Indicates initial feed hold is complete.
|
||||
#define SUSPEND_RESTART_RETRACT bit(1) // Flag to indicate a retract from a restore parking motion.
|
||||
#define SUSPEND_RETRACT_COMPLETE bit(2) // (Safety door only) Indicates retraction and de-energizing is complete.
|
||||
#define SUSPEND_INITIATE_RESTORE bit(3) // (Safety door only) Flag to initiate resume procedures from a cycle start.
|
||||
#define SUSPEND_RESTORE_COMPLETE bit(4) // (Safety door only) Indicates ready to resume normal operation.
|
||||
#define SUSPEND_SAFETY_DOOR_AJAR bit(5) // Tracks safety door state for resuming.
|
||||
#define SUSPEND_MOTION_CANCEL bit(6) // Indicates a canceled resume motion. Currently used by probing routine.
|
||||
#define SUSPEND_JOG_CANCEL bit(7) // Indicates a jog cancel in process and to reset buffers when complete.
|
||||
#define SUSPEND_DISABLE 0 // Must be zero.
|
||||
#define SUSPEND_HOLD_COMPLETE bit(0) // Indicates initial feed hold is complete.
|
||||
#define SUSPEND_RESTART_RETRACT bit(1) // Flag to indicate a retract from a restore parking motion.
|
||||
#define SUSPEND_RETRACT_COMPLETE bit(2) // (Safety door only) Indicates retraction and de-energizing is complete.
|
||||
#define SUSPEND_INITIATE_RESTORE bit(3) // (Safety door only) Flag to initiate resume procedures from a cycle start.
|
||||
#define SUSPEND_RESTORE_COMPLETE bit(4) // (Safety door only) Indicates ready to resume normal operation.
|
||||
#define SUSPEND_SAFETY_DOOR_AJAR bit(5) // Tracks safety door state for resuming.
|
||||
#define SUSPEND_MOTION_CANCEL bit(6) // Indicates a canceled resume motion. Currently used by probing routine.
|
||||
#define SUSPEND_JOG_CANCEL bit(7) // Indicates a jog cancel in process and to reset buffers when complete.
|
||||
|
||||
// Define step segment generator state flags.
|
||||
#define STEP_CONTROL_NORMAL_OP 0 // Must be zero.
|
||||
#define STEP_CONTROL_END_MOTION bit(0)
|
||||
#define STEP_CONTROL_EXECUTE_HOLD bit(1)
|
||||
#define STEP_CONTROL_EXECUTE_SYS_MOTION bit(2)
|
||||
#define STEP_CONTROL_UPDATE_SPINDLE_PWM bit(3)
|
||||
#define STEP_CONTROL_NORMAL_OP 0 // Must be zero.
|
||||
#define STEP_CONTROL_END_MOTION bit(0)
|
||||
#define STEP_CONTROL_EXECUTE_HOLD bit(1)
|
||||
#define STEP_CONTROL_EXECUTE_SYS_MOTION bit(2)
|
||||
#define STEP_CONTROL_UPDATE_SPINDLE_PWM bit(3)
|
||||
|
||||
// Define control pin index for Grbl internal use. Pin maps may change, but these values don't.
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
#define N_CONTROL_PIN 4
|
||||
#define CONTROL_PIN_INDEX_SAFETY_DOOR bit(0)
|
||||
#define CONTROL_PIN_INDEX_RESET bit(1)
|
||||
#define CONTROL_PIN_INDEX_FEED_HOLD bit(2)
|
||||
#define CONTROL_PIN_INDEX_CYCLE_START bit(3)
|
||||
#define N_CONTROL_PIN 4
|
||||
#define CONTROL_PIN_INDEX_SAFETY_DOOR bit(0)
|
||||
#define CONTROL_PIN_INDEX_RESET bit(1)
|
||||
#define CONTROL_PIN_INDEX_FEED_HOLD bit(2)
|
||||
#define CONTROL_PIN_INDEX_CYCLE_START bit(3)
|
||||
#else
|
||||
#define N_CONTROL_PIN 3
|
||||
#define CONTROL_PIN_INDEX_RESET bit(0)
|
||||
#define CONTROL_PIN_INDEX_FEED_HOLD bit(1)
|
||||
#define CONTROL_PIN_INDEX_CYCLE_START bit(2)
|
||||
#define N_CONTROL_PIN 3
|
||||
#define CONTROL_PIN_INDEX_RESET bit(0)
|
||||
#define CONTROL_PIN_INDEX_FEED_HOLD bit(1)
|
||||
#define CONTROL_PIN_INDEX_CYCLE_START bit(2)
|
||||
#endif
|
||||
|
||||
// Define spindle stop override control states.
|
||||
#define SPINDLE_STOP_OVR_DISABLED 0 // Must be zero.
|
||||
#define SPINDLE_STOP_OVR_ENABLED bit(0)
|
||||
#define SPINDLE_STOP_OVR_INITIATE bit(1)
|
||||
#define SPINDLE_STOP_OVR_RESTORE bit(2)
|
||||
#define SPINDLE_STOP_OVR_RESTORE_CYCLE bit(3)
|
||||
|
||||
#define SPINDLE_STOP_OVR_DISABLED 0 // Must be zero.
|
||||
#define SPINDLE_STOP_OVR_ENABLED bit(0)
|
||||
#define SPINDLE_STOP_OVR_INITIATE bit(1)
|
||||
#define SPINDLE_STOP_OVR_RESTORE bit(2)
|
||||
#define SPINDLE_STOP_OVR_RESTORE_CYCLE bit(3)
|
||||
|
||||
// Define global system variables
|
||||
typedef struct {
|
||||
uint8_t state; // Tracks the current system state of Grbl.
|
||||
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
|
||||
uint8_t suspend; // System suspend bitflag variable that manages holds, cancels, and safety door.
|
||||
uint8_t soft_limit; // Tracks soft limit errors for the state machine. (boolean)
|
||||
uint8_t step_control; // Governs the step segment generator depending on system state.
|
||||
uint8_t probe_succeeded; // Tracks if last probing cycle was successful.
|
||||
uint8_t homing_axis_lock; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
uint8_t state; // Tracks the current system state of Grbl.
|
||||
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
|
||||
uint8_t suspend; // System suspend bitflag variable that manages holds, cancels, and safety door.
|
||||
uint8_t soft_limit; // Tracks soft limit errors for the state machine. (boolean)
|
||||
uint8_t step_control; // Governs the step segment generator depending on system state.
|
||||
uint8_t probe_succeeded; // Tracks if last probing cycle was successful.
|
||||
uint8_t homing_axis_lock; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
|
||||
#ifdef ENABLE_DUAL_AXIS
|
||||
uint8_t homing_axis_lock_dual;
|
||||
#endif
|
||||
uint8_t f_override; // Feed rate override value in percent
|
||||
uint8_t r_override; // Rapids override value in percent
|
||||
uint8_t spindle_speed_ovr; // Spindle speed value in percent
|
||||
uint8_t spindle_stop_ovr; // Tracks spindle stop override states
|
||||
uint8_t report_ovr_counter; // Tracks when to add override data to status reports.
|
||||
uint8_t report_wco_counter; // Tracks when to add work coordinate offset data to status reports.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
uint8_t override_ctrl; // Tracks override control states.
|
||||
#endif
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
#endif
|
||||
uint8_t f_override; // Feed rate override value in percent
|
||||
uint8_t r_override; // Rapids override value in percent
|
||||
uint8_t spindle_speed_ovr; // Spindle speed value in percent
|
||||
uint8_t spindle_stop_ovr; // Tracks spindle stop override states
|
||||
uint8_t report_ovr_counter; // Tracks when to add override data to status reports.
|
||||
uint8_t report_wco_counter; // Tracks when to add work coordinate offset data to status reports.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
uint8_t override_ctrl; // Tracks override control states.
|
||||
#endif
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
float spindle_speed;
|
||||
#endif
|
||||
#endif
|
||||
} system_t;
|
||||
|
||||
extern system_t sys;
|
||||
|
||||
// NOTE: These position variables may need to be declared as volatiles, if problems arise.
|
||||
extern int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
extern int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
extern int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
|
||||
extern volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
extern volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
extern volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
extern volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
extern volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
extern volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
extern volatile uint8_t
|
||||
sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
extern volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
extern volatile uint8_t
|
||||
sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
extern volatile uint8_t
|
||||
sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EXEC_DEBUG_REPORT bit(0)
|
||||
extern volatile uint8_t sys_rt_exec_debug;
|
||||
#define EXEC_DEBUG_REPORT bit(0)
|
||||
extern volatile uint8_t sys_rt_exec_debug;
|
||||
#endif
|
||||
|
||||
// Initialize the serial protocol
|
||||
|
|
@ -180,7 +183,6 @@ uint8_t system_execute_line(char *line);
|
|||
// Execute the startup script lines stored in EEPROM upon initialization
|
||||
void system_execute_startup(char *line);
|
||||
|
||||
|
||||
void system_flag_wco_change();
|
||||
|
||||
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
|
||||
|
|
@ -191,8 +193,8 @@ void system_convert_array_steps_to_mpos(float *position, int32_t *steps);
|
|||
|
||||
// CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps.
|
||||
#ifdef COREXY
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps);
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps);
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps);
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps);
|
||||
#endif
|
||||
|
||||
// Checks and reports if target array exceeds machine travel limits.
|
||||
|
|
@ -208,5 +210,4 @@ void system_set_exec_accessory_override_flag(uint8_t mask);
|
|||
void system_clear_exec_motion_overrides();
|
||||
void system_clear_exec_accessory_overrides();
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue