diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..8cc6ea15f
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: Gauthier
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.gitignore b/.gitignore
index b61325d28..c184355f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,11 @@
*.hex
+*.zip
*.o
*.elf
*.DS_Store
*.d
+.grbl*
+.vscode
+platformio.ini
README.md
diff --git a/COPYING b/COPYING
index de86f6fb5..93fa11bd1 100644
--- a/COPYING
+++ b/COPYING
@@ -4,6 +4,7 @@ COPYRIGHT NOTICE FOR GRBL:
Grbl - Embedded CNC g-code interpreter and motion-controller
+Copyright (c) 2017-2018 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Jens Geisler
diff --git a/Makefile b/Makefile
index 6d97edfba..573f604c6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
# Part of Grbl
#
+# Copyright (c) 2017-2022 Gauthier Briere
# Copyright (c) 2009-2011 Simen Svale Skogsrud
# Copyright (c) 2012-2015 Sungeun K. Jeon
#
@@ -30,12 +31,17 @@
DEVICE ?= atmega2560
CLOCK = 16000000L
-PROGRAMMER ?= -c avrisp2 -P usb
-SOURCE = main.c motion_control.c gcode.c spindle_control.c coolant_control.c serial.c \
- protocol.c stepper.c eeprom.c settings.c planner.c nuts_bolts.c limits.c \
- print.c probe.c report.c system.c sleep.c jog.c
+
+DEVICE_PORT ?= /dev/ttyUSB0
+PROGRAMMER ?= -D -v -c avrisp2 -P $(DEVICE_PORT)
+
+SOURCE = main.c motion_control.c gcode.c spindle_control.c coolant_control.c digital_control.c\
+ analog_control.c serial.c protocol.c stepper.c eeprom.c settings.c planner.c nuts_bolts.c\
+ limits.c print.c probe.c report.c system.c sleep.c jog.c
+
BUILDDIR = build
SOURCEDIR = grbl
+
# FUSES = -U hfuse:w:0xd9:m -U lfuse:w:0x24:m
FUSES = -U hfuse:w:0xd2:m -U lfuse:w:0xff:m
@@ -47,7 +53,7 @@ AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) -B 10 -F
# COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections
# Compile flags for avr-gcc v4.9.2 compatible with the IDE. Or if you don't care about the warnings.
-COMPILE = avr-gcc -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections -flto
+COMPILE = avr-gcc $(CFLAGS) -Wall -Os -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -I. -ffunction-sections -flto
OBJECTS = $(addprefix $(BUILDDIR)/,$(notdir $(SOURCE:.c=.o)))
diff --git a/README.md b/README.md
index aa6a772b3..8d89f58ff 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
-![GitHub Logo](https://github.com/gnea/gnea-Media/blob/master/Grbl%20Logo/Grbl%20Logo%20250px.png?raw=true)
-***
-_Click the `Release` tab to download pre-compiled `.hex` files or just [click here](https://github.com/gnea/grbl-Mega/releases)_
+![GitHub Logo](https://github.com/fra589/grbl-Mega-5X/blob/edge/doc/images/Mega-5X-logo.svg)
+
***
Grbl is a no-compromise, high performance, low cost alternative to parallel-port-based motion control for CNC milling. This version of Grbl runs on an Arduino Mega2560 only.
@@ -11,19 +10,13 @@ It accepts standards-compliant g-code and has been tested with the output of sev
Grbl includes full acceleration management with look ahead. That means the controller will look up to 24 motions into the future and plan its velocities ahead to deliver smooth acceleration and jerk-free cornering.
-* [Licensing](https://github.com/gnea/grbl/wiki/Licensing): Grbl is free software, released under the GPLv3 license.
+* [Licensing](https://github.com/fra589/grbl-Mega-5X/blob/edge/COPYING): Grbl is free software, released under the GPLv3 license.
-* For more information and help, check out our **[Wiki pages!](https://github.com/gnea/grbl/wiki)** If you find that the information is out-dated, please to help us keep it updated by editing it or notifying our community! Thanks!
+* For more information and help, check out our **[Wiki pages!](https://github.com/fra589/grbl-Mega-5X/wiki)** If you find that the information is out-dated, please to help us keep it updated by editing it or notifying our community! Thanks!
-* Lead Developer: Sungeun "Sonny" Jeon, Ph.D. (USA) aka @chamnit
-
-* Built on the wonderful Grbl v0.6 (2011) firmware written by Simen Svale Skogsrud (Norway).
-
-***
-
-### Official Supporters of the Grbl CNC Project
-![Official Supporters](https://github.com/gnea/gnea-Media/blob/master/Contributors.png?raw=true)
+* Lead Developer: Gauthier Brière (France) aka @fra589
+* Built on the wonderful Grbl v1.1f (2017) firmware originally written by Simen Svale Skogsrud (Norway) and maintained by Sungeun "Sonny" Jeon, Ph.D. (USA) aka @chamnit
***
@@ -58,8 +51,6 @@ Grbl includes full acceleration management with look ahead. That means the contr
- Lots of minor bug fixes and refactoring to make the code more efficient and flexible.
-
-
```
List of Supported G-Codes in Grbl v1.1:
- Non-Modal Commands: G4, G10L2, G10L20, G28, G30, G28.1, G30.1, G53, G92, G92.1
@@ -76,10 +67,8 @@ List of Supported G-Codes in Grbl v1.1:
- Program Flow: M0, M1, M2, M30*
- Coolant Control: M7*, M8, M9
- Spindle Control: M3, M4, M5
- - Valid Non-Command Words: F, I, J, K, L, N, P, R, S, T, X, Y, Z
+ - Valid Non-Command Words: F, I, J, K, L, N, P, R, S, T, X, Y, Z, A, B, C
```
-------------
-Grbl is an open-source project and fueled by the free-time of our intrepid administrators and altruistic users. If you'd like to donate, all proceeds will be used to help fund supporting hardware and testing equipment. Thank you!
-
-[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CUGXJHXA36BYW)
+Grbl-Mega-5X is an open-source project and fueled by the free-time of our intrepid administrators and altruistic users. If you'd like to donate, all proceeds will be used to help fund supporting hardware and testing equipment. Thank you! [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?business=CZZN52UPPVHCW&no_recurring=0&item_name=Grbl-Mega-5X+%26+cn5X%2B%2B+donations¤cy_code=EUR)
diff --git a/TODO b/TODO
new file mode 100644
index 000000000..7667e7f3b
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+Square offset params
+backlash compensation
+#112 => 2 PWM outputs: One on D8 in 0-12V and the other on another port in 0-5V, new commands such as M3.1, M4.1 and M5.1 to control the second output.
+#71 => G0 should find the shortest path on Rotary Axis (wrap-around coordinate system ?)
+CoreXY homing bug correction grbl-Mega-5X #124 / grbl-Mega #49
+Second serial port communications
+Spindle enable (laser enable) did not restore after feed hold, bug #79
+Implementy analog output (PWM output) M67/M68
+
+
diff --git a/doc/csv/alarm_codes_en_US.csv b/doc/csv/alarm_codes_en_US.csv
index 1ab2b8ae5..68d168c0d 100644
--- a/doc/csv/alarm_codes_en_US.csv
+++ b/doc/csv/alarm_codes_en_US.csv
@@ -8,3 +8,5 @@
"7","Homing fail","Homing fail. Safety door was opened during homing cycle."
"8","Homing fail","Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring."
"9","Homing fail","Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring."
+"10","Homing fail","Homing fail. Max travel is shorter than the pull off travel."
+"11","Serial overflow","Serial RX buffer overflow."
diff --git a/doc/csv/build_option_codes_en_US.csv b/doc/csv/build_option_codes_en_US.csv
index f7abb8fe5..90540d394 100644
--- a/doc/csv/build_option_codes_en_US.csv
+++ b/doc/csv/build_option_codes_en_US.csv
@@ -1,21 +1,23 @@
-"OPT: Code"," Build-Option Description","State"
+"OPT: Code","Build-Option Description","State"
"V","Variable spindle","Enabled"
"N","Line numbers","Enabled"
"M","Mist coolant M7","Enabled"
+"G","Safety door input pin","Enabled"
"C","CoreXY","Enabled"
"P","Parking motion","Enabled"
"Z","Homing force origin","Enabled"
"H","Homing single axis commands","Enabled"
"T","Two limit switches on axis","Enabled"
+"S","Use different spindle output pin in laser mode","Enabled"
+"D","Digital input","Enabled"
+"Q","Analog output (PWM)","Enabled"
"A","Allow feed rate overrides in probe cycles","Enabled"
-"D","Use spindle direction as enable pin","Enabled"
"0","Spindle enable off when speed is zero","Enabled"
-"S","Software limit pin debouncing","Enabled"
"R","Parking override control","Enabled"
+"L","Homing initialization auto-lock","Disabled"
"*","Restore all EEPROM command","Disabled"
"$","Restore EEPROM `$` settings command","Disabled"
"#","Restore EEPROM parameter data command","Disabled"
"I","Build info write user string command","Disabled"
"E","Force sync upon EEPROM write","Disabled"
"W","Force sync upon work coordinate offset change","Disabled"
-"L","Homing initialization auto-lock","Disabled"
\ No newline at end of file
diff --git a/doc/csv/error_codes_en_US.csv b/doc/csv/error_codes_en_US.csv
index 1375945aa..c7448c679 100644
--- a/doc/csv/error_codes_en_US.csv
+++ b/doc/csv/error_codes_en_US.csv
@@ -34,4 +34,4 @@
"35","Invalid gcode ID:35","G2 and G3 arcs require at least one in-plane offset word."
"36","Invalid gcode ID:36","Unused value words found in block."
"37","Invalid gcode ID:37","G43.1 dynamic tool length offset is not assigned to configured tool length axis."
-"38","Invalid gcode ID:38","Tool number greater than max supported value."
\ No newline at end of file
+"38","Invalid gcode ID:38","Tool number or digital output number greater than max supported value."
diff --git a/doc/csv/setting_codes_en_US.csv b/doc/csv/setting_codes_en_US.csv
index fb97a3f3c..11696b5ad 100644
--- a/doc/csv/setting_codes_en_US.csv
+++ b/doc/csv/setting_codes_en_US.csv
@@ -21,15 +21,27 @@
"30","Maximum spindle speed","RPM","Maximum spindle speed. Sets PWM to 100% duty cycle."
"31","Minimum spindle speed","RPM","Minimum spindle speed. Sets PWM to 0.4% or lowest duty cycle."
"32","Laser-mode enable","boolean","Enables laser mode. Consecutive G1/2/3 commands will not halt when spindle speed is changed."
+"33","Maximum laser value","Laser unit","Maximum laser value. Sets PWM to 100% duty cycle."
+"34","Minimum laser value","Laser unit","Minimum laser value. Sets PWM to 0.4% or lowest duty cycle."
+"35","Maximum output value","Volts or other units","Maximum output value. Sets PWM to 100% duty cycle."
+"36","Minimum output value","Volts or other units","Minimum output value. Sets PWM to 0.4% or lowest duty cycle."
"100","X-axis travel resolution","step/mm","X-axis travel resolution in steps per millimeter."
"101","Y-axis travel resolution","step/mm","Y-axis travel resolution in steps per millimeter."
"102","Z-axis travel resolution","step/mm","Z-axis travel resolution in steps per millimeter."
+"103","A-axis travel resolution","step/degre","A-Axis travel resolution in steps per degre"
+"104","B-axis travel resolution","step/degre","B-Axis travel resolution in steps per degre"
"110","X-axis maximum rate","mm/min","X-axis maximum rate. Used as G0 rapid rate."
"111","Y-axis maximum rate","mm/min","Y-axis maximum rate. Used as G0 rapid rate."
"112","Z-axis maximum rate","mm/min","Z-axis maximum rate. Used as G0 rapid rate."
+"113","A-axis maximum rate","degre/min","A-axis maximum rate. Used as G0 rapid rate"
+"114","B-axis maximum rate","degre/min","B-axis maximum rate. Used as G0 rapid rate"
"120","X-axis acceleration","mm/sec^2","X-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
"121","Y-axis acceleration","mm/sec^2","Y-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
"122","Z-axis acceleration","mm/sec^2","Z-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
+"123","A-Axis acceleration","degre/sec^2","A-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
+"124","B-Axis acceleration","degre/sec^2","B-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
"130","X-axis maximum travel","millimeters","Maximum X-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
"131","Y-axis maximum travel","millimeters","Maximum Y-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
"132","Z-axis maximum travel","millimeters","Maximum Z-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
+"133","A-axis maximum travel","degres","Maximum A-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
+"134","B-axis maximum travel","degres","Maximum B-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
diff --git a/doc/images/Mega-5X-logo.svg b/doc/images/Mega-5X-logo.svg
new file mode 100644
index 000000000..e850c4f67
--- /dev/null
+++ b/doc/images/Mega-5X-logo.svg
@@ -0,0 +1,152 @@
+
+
+
+
diff --git a/doc/images/arduino-mega-pinout-detail.png b/doc/images/arduino-mega-pinout-detail.png
new file mode 100644
index 000000000..47306d47f
Binary files /dev/null and b/doc/images/arduino-mega-pinout-detail.png differ
diff --git a/doc/images/arduino-mega-pinout-diagram.png b/doc/images/arduino-mega-pinout-diagram.png
new file mode 100644
index 000000000..b4d3f719b
Binary files /dev/null and b/doc/images/arduino-mega-pinout-diagram.png differ
diff --git a/doc/images/grbl-Mega-5X_Wiring.svg b/doc/images/grbl-Mega-5X_Wiring.svg
new file mode 100644
index 000000000..e3d5f46b0
--- /dev/null
+++ b/doc/images/grbl-Mega-5X_Wiring.svg
@@ -0,0 +1,3433 @@
+
+
diff --git a/doc/log/commit_log_v1.0d.txt b/doc/log/commit_log_v1.0d.txt
index 7c9462c60..422cf125d 100644
--- a/doc/log/commit_log_v1.0d.txt
+++ b/doc/log/commit_log_v1.0d.txt
@@ -1,3 +1,50 @@
+----------------
+Date: 2018-08-13
+Author: Sonny Jeon
+Subject: Merge branch 'edge' of https://github.com/gnea/grbl-Mega into edge
+
+
+----------------
+Date: 2018-08-13
+Author: Sonny Jeon
+Subject: Upstream updates. Spindle/coolant rare bug fixes.
+
+[new] Altered the way default settings are stored and restored. Saved about 300 bytes(!) of flashed size. Should free up enough for certain configurations of CoreXY machines.
+
+[fix] When the optional M7 mist coolant IO was enabled, coolant overrides was not disabling correctly.
+
+[fix] Coolant override states was not restored correctly after a parking motion in certain situations. It would restore programmed state, rather than current overridden state.
+
+[fix] Now allow coolant overrides to operate during jogging motion.
+
+[fix] Invert control pin mask typo.
+
+[new] Added a new build info feedback mechanism for enabling the safety door input pin.
+
+
+----------------
+Date: 2018-08-10
+Author: Sonny Jeon
+Subject: Merge pull request #68 from bgort/gremlinfix
+
+Fixes gremlin where changing step and direction inversion masks made a mess
+
+----------------
+Date: 2018-08-10
+Author: Brian
+Subject: fixes gremlin where changing stepper direction mask didn't work correctly
+because step_port_invert_mask[] (new with the RAMPS modifications)
+wasn't reset to 0 when it should have been. this made a mess.
+
+
+----------------
+Date: 2017-08-02
+Author: Sonny Jeon
+Subject: Fixed a very rare but critical bug when reducing override rates.
+
+- See main branch commit log for details.
+
+
----------------
Date: 2017-08-01
Author: Sonny Jeon
diff --git a/doc/markdown/interface.md b/doc/markdown/interface.md
index 184603e04..aaa741d9b 100644
--- a/doc/markdown/interface.md
+++ b/doc/markdown/interface.md
@@ -136,7 +136,7 @@ Every G-code block sent to Grbl and Grbl `$` system command that is terminated w
* **`error:X`**: Something went wrong! Grbl did not recognize the command and did not execute anything inside that message. The `X` is given as a numeric error code to tell you exactly what happened. The table below decribes every one of them.
- | ID | Error Code Description |
+| ID | Error Code Description |
|:-------------:|----|
| **`1`** | G-code words consist of a letter and a value. Letter was not found. |
| **`2`** | Numeric value format is not valid or missing an expected value. |
@@ -266,19 +266,27 @@ $32=0
$100=250.000
$101=250.000
$102=250.000
+$103=8.888889
+$104=8.888889
$110=500.000
$111=500.000
$112=500.000
+$113=1440.000
+$114=1440.000
$120=10.000
$121=10.000
$122=10.000
+$123=1000.000
+$124=1000.000
$130=200.000
$131=200.000
$132=200.000
+$133=180.000
+$134=360.000
ok
```
- | `$x` Code | Setting Description, Units |
+| `$x` Code | Setting Description, Units |
|:-------------:|----|
| **`0`** | Step pulse time, microseconds |
| **`1`** | Step idle delay, milliseconds |
@@ -305,16 +313,23 @@ ok
| **`100`** | X-axis steps per millimeter |
| **`101`** | Y-axis steps per millimeter |
| **`102`** | Z-axis steps per millimeter |
+| **`103`** | A-axis steps per degre |
+| **`104`** | B-axis steps per degre |
| **`110`** | X-axis maximum rate, mm/min |
| **`111`** | Y-axis maximum rate, mm/min |
| **`112`** | Z-axis maximum rate, mm/min |
+| **`113`** | A-axis maximum rate, degres/min |
+| **`114`** | B-axis maximum rate, degres/min |
| **`120`** | X-axis acceleration, mm/sec^2 |
| **`121`** | Y-axis acceleration, mm/sec^2 |
| **`122`** | Z-axis acceleration, mm/sec^2 |
+| **`123`** | A-axis acceleration, degres/sec^2 |
+| **`124`** | B-axis acceleration, degres/sec^2 |
| **`130`** | X-axis maximum travel, millimeters |
| **`131`** | Y-axis maximum travel, millimeters |
| **`132`** | Z-axis maximum travel, millimeters |
-
+| **`133`** | A-axis maximum travel, degres |
+| **`134`** | B-axis maximum travel, degres |
- The other `$Nx=line` message is the print-out of a user-defined startup line, where `x` denotes the startup line order and ranges from `0` to `1` by default. The `line` denotes the startup line to be executed by Grbl upon reset or power-up, except during an ALARM.
@@ -418,7 +433,7 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
- A string may appear after the second `:` colon. It is a stored EEPROM string a user via a `$I=line` command or OEM can place there for personal use or tracking purposes.
- The `[OPT:]` line follows immediately after and contains character codes for compile-time options that were either enabled or disabled and two values separated by commas, which indicates the total usable planner blocks and serial RX buffer bytes, respectively. The codes are defined below and a CSV file is also provided for quick parsing. This is generally only used for quickly diagnosing firmware bugs or compatibility issues.
- | `OPT` Code | Setting Description, Units |
+| `OPT` Code | Setting Description, Units |
|:-------------:|----|
| **`V`** | Variable spindle enabled |
| **`N`** | Line numbers enabled |
@@ -433,6 +448,7 @@ Feedback messages provide non-critical information on what Grbl is doing, what i
| **`S`** | Software limit pin debouncing enabled |
| **`R`** | Parking override control enabled |
| **`A`** | Allow feed rate overrides in probe cycles |
+| **`G`** | Safety door input pin enabled |
| **`*`** | Restore all EEPROM disabled |
| **`$`** | Restore EEPROM `$` settings disabled |
| **`#`** | Restore EEPROM parameter data disabled |
diff --git a/doc/markdown/settings.md b/doc/markdown/settings.md
index 4b54746f3..1c5c26856 100644
--- a/doc/markdown/settings.md
+++ b/doc/markdown/settings.md
@@ -54,15 +54,23 @@ $32=0
$100=250.000
$101=250.000
$102=250.000
+$103=8.888889
+$104=8.888889
$110=500.000
$111=500.000
$112=500.000
+$113=1440.000
+$114=1440.000
$120=10.000
$121=10.000
$122=10.000
+$123=1000.000
+$124=1000.000
$130=200.000
$131=200.000
$132=200.000
+$133=180.000
+$134=360.000
```
#### $x=val - Save Grbl setting
@@ -98,16 +106,40 @@ This setting inverts the step pulse signal. By default, a step signal starts at
This invert mask setting is a value which stores the axes to invert as bit flags. You really don't need to completely understand how it works. You simply need to enter the settings value for the axes you want to invert. For example, if you want to invert the X and Z axes, you'd send `$2=5` to Grbl and the setting should now read `$2=5 (step port invert mask:00000101)`.
-| Setting Value | Mask |Invert X | Invert Y | Invert Z |
-|:-------------:|:----:|:-------:|:--------:|:--------:|
-| 0 | 00000000 |N | N | N |
-| 1 | 00000001 |Y | N | N |
-| 2 | 00000010 |N | Y | N |
-| 3 | 00000011 |Y | Y | N |
-| 4 | 00000100 |N | N | Y |
-| 5 | 00000101 |Y | N | Y |
-| 6 | 00000110 |N | Y | Y |
-| 7 | 00000111 |Y | Y | Y |
+| Setting Value | Mask | Invert X | Invert Y | Invert Z | Invert A | Invert B |
+|:-------------:|:--------:|:--------:|:--------:|:--------:|:--------:|:--------:|
+| 0 | 00000000 | N | N | N | N | N |
+| 1 | 00000001 | Y | N | N | N | N |
+| 2 | 00000010 | N | Y | N | N | N |
+| 3 | 00000011 | Y | Y | N | N | N |
+| 4 | 00000100 | N | N | Y | N | N |
+| 5 | 00000101 | Y | N | Y | N | N |
+| 6 | 00000110 | N | Y | Y | N | N |
+| 7 | 00000111 | Y | Y | Y | N | N |
+| 8 | 00001000 | N | N | N | Y | N |
+| 9 | 00001001 | Y | N | N | Y | N |
+| 10 | 00001010 | N | Y | N | Y | N |
+| 11 | 00001011 | Y | Y | N | Y | N |
+| 12 | 00001100 | N | N | Y | Y | N |
+| 13 | 00001101 | Y | N | Y | Y | N |
+| 14 | 00001110 | N | Y | Y | Y | N |
+| 15 | 00001111 | Y | Y | Y | Y | N |
+| 16 | 00010000 | N | N | N | N | Y |
+| 17 | 00010001 | Y | N | N | N | Y |
+| 18 | 00010010 | N | Y | N | N | Y |
+| 19 | 00010011 | Y | Y | N | N | Y |
+| 20 | 00010100 | N | N | Y | N | Y |
+| 21 | 00010101 | Y | N | Y | N | Y |
+| 22 | 00010110 | N | Y | Y | N | Y |
+| 23 | 00010111 | Y | Y | Y | N | Y |
+| 24 | 00011000 | N | N | N | Y | Y |
+| 25 | 00011001 | Y | N | N | Y | Y |
+| 26 | 00011010 | N | Y | N | Y | Y |
+| 27 | 00011011 | Y | Y | N | Y | Y |
+| 28 | 00011100 | N | N | Y | Y | Y |
+| 29 | 00011101 | Y | N | Y | Y | Y |
+| 30 | 00011110 | N | Y | Y | Y | Y |
+| 31 | 00011111 | Y | Y | Y | Y | Y |
#### $3 – Direction port invert, mask
@@ -146,9 +178,9 @@ To keep things simple and consistent, Grbl v1.1 has only two reporting options.
Use the table below enables and disable reporting options. Simply add the values listed of what you'd like to enable, then save it by sending Grbl your setting value. For example, the default report with machine position and no buffer data reports setting is `$10=1`. If work position and buffer data are desired, the setting will be `$10=2`.
| Report Type | Value | Description |
-|:-------------:|:----:|:----:|
+|:-------------:|:-----:|:-------------------------------------------------------------------------:|
| Position Type | 1 | Enabled `MPos:`. Disabled `WPos:`. |
-| Buffer Data | 2 | Enabled `Buf:` field appears with planner and serial RX available buffer.
+| Buffer Data | 2 | Enabled `Buf:` field appears with planner and serial RX available buffer. |
#### $11 - Junction deviation, mm
@@ -237,6 +269,9 @@ Grbl needs to know how far each step will take the tool in reality. To calculate
The steps/mm can then be calculated like this: ```steps_per_mm = (steps_per_revolution*microsteps)/mm_per_rev```
+#### $103 AND $104 - [A,B] steps/degre
+Idem than step/mm, but for rotational axis 4 and 5
+
Compute this value for every axis and write these settings to Grbl.
#### $110, $111 and $112 – [X,Y,Z] Max rate, mm/min
@@ -247,13 +282,22 @@ The simplest way to determine these values is to test each axis one at a time by
NOTE: This max rate setting also sets the G0 seek rates.
+#### $113 and $114 - [A,B] Max rate, degre/min
+
+Maximum rate for rotational axis
+
+
#### $120, $121, $122 – [X,Y,Z] Acceleration, mm/sec^2
This sets the axes acceleration parameters in mm/second/second. Simplistically, a lower value makes Grbl ease slower into motion, while a higher value yields tighter moves and reaches the desired feed rates much quicker. Much like the max rate setting, each axis has its own acceleration value and are independent of each other. This means that a multi-axis motion will only accelerate as quickly as the lowest contributing axis can.
Again, like the max rate setting, the simplest way to determine the values for this setting is to individually test each axis with slowly increasing values until the motor stalls. Then finalize your acceleration setting with a value 10-20% below this absolute max value. This should account for wear, friction, and mass inertia. We highly recommend that you dry test some G-code programs with your new settings before committing to them. Sometimes the loading on your machine is different when moving in all axes together.
+#### $123 and $124 - [A,B] Acceleration, degre/sec^2
+
#### $130, $131, $132 – [X,Y,Z] Max travel, mm
This sets the maximum travel from end to end for each axis in mm. This is only useful if you have soft limits (and homing) enabled, as this is only used by Grbl's soft limit feature to check if you have exceeded your machine limits with a motion command.
+
+#### $133, $134 - [A,B] Max travel, degres
diff --git a/doc/script/simple_stream.py b/doc/script/simple_stream.py
old mode 100755
new mode 100644
diff --git a/doc/script/stream.py b/doc/script/stream.py
old mode 100755
new mode 100644
diff --git a/grbl/analog_control.c b/grbl/analog_control.c
new file mode 100644
index 000000000..4748902e5
--- /dev/null
+++ b/grbl/analog_control.c
@@ -0,0 +1,124 @@
+/*
+ analog_control.c - Read analog input
+ Part of Grbl
+
+ Copyright (c) 2017-2022 Gauthier Briere
+
+ Grbl is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Grbl is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grbl. If not, see .
+*/
+
+#include "grbl.h"
+
+
+#ifdef USE_OUTPUT_PWM
+
+static float output_pwm_gradient; // Precalulated value to speed up volts to PWM conversions.
+
+float o_pwm_gradient()
+{
+ return output_pwm_gradient;
+}
+
+void output_pwm_init()
+{
+ // Force PWM output zero to avoid PWM output flash on laser output
+ OUTPUT_TCCRA_REGISTER &= ~(1<= settings.volts_max) || (volts >= settings.volts_max)) {
+ // No PWM range possible. Set simple on/off output control pin state.
+ sys.output_volts = settings.volts_max;
+ pwm_value = OUTPUT_PWM_MAX_VALUE;
+ } else if (volts <= settings.volts_min) {
+ if (volts == 0.0) { // S0 disables output
+ sys.output_volts = 0.0;
+ pwm_value = OUTPUT_PWM_OFF_VALUE;
+ } else { // Set minimum PWM output
+ sys.output_volts = settings.volts_min;
+ pwm_value = OUTPUT_PWM_MIN_VALUE;
+ }
+ } else {
+ // Compute intermediate PWM value with linear output volts model.
+ // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
+ sys.output_volts = volts;
+ pwm_value = floor((volts - settings.volts_min)*output_pwm_gradient) + OUTPUT_PWM_MIN_VALUE;
+ }
+ return(pwm_value);
+}
+
+void output_pwm_set_state(uint8_t state, float volts)
+{
+ if (sys.abort) { return; } // Block during abort.
+ if (state == OUTPUT_PWM_STATE_OFF) { // Stop output PWM.
+ sys.output_volts = 0.0;
+ output_pwm_stop();
+ } else {
+ // NOTE: In laser mode, output will be active only when moving (STATE_CYCLE) or sleeping (STATE_SLEEP)
+ if (settings.flags & BITFLAG_LASER_MODE) {
+ if ((sys.state == STATE_IDLE) || (sys.state & (STATE_ALARM | STATE_CHECK_MODE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR ))) {
+ volts = 0.0;
+ }
+ }
+ output_pwm_set_value(output_compute_pwm_value(volts));
+ }
+ // Set to report change immediately
+ sys.report_ovr_counter = 0;
+}
+
+// G-code parser entry-point for setting output PWM state. Forces a planner buffer sync and bails
+// if an abort or check-mode is active.
+void output_pwm_sync(uint8_t state, float volts)
+{
+ if (sys.state == STATE_CHECK_MODE) { return; }
+ protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
+ output_pwm_set_state(state, volts);
+}
+
+#endif // USE_OUTPUT_PWM
+
diff --git a/grbl/analog_control.h b/grbl/analog_control.h
new file mode 100644
index 000000000..fe7afe7d8
--- /dev/null
+++ b/grbl/analog_control.h
@@ -0,0 +1,47 @@
+/*
+ analog_control.h - Read analog input
+ Part of Grbl
+
+ Copyright (c) 2017-2022 Gauthier Briere
+
+ Grbl is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Grbl is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grbl. If not, see .
+*/
+
+#ifndef analog_control_h
+#define analog_control_h
+
+#define OUTPUT_PWM_STATE_OFF 0 // Must be 0
+#define OUTPUT_PWM_STATE_ON bit(0)
+
+#ifndef cbi
+ #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+#ifndef sbi
+ #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+#ifdef USE_OUTPUT_PWM
+
+float o_pwm_gradient();
+
+ void output_pwm_init();
+ uint8_t output_pwm_get_state();
+ void output_pwm_stop();
+ void output_pwm_set_value(uint16_t pwm_value);
+ uint16_t output_compute_pwm_value(float volts);
+ void output_pwm_set_state(uint8_t state, float volts);
+ void output_pwm_sync(uint8_t state, float volts);
+#endif // USE_OUTPUT_PWM
+
+#endif
diff --git a/grbl/config.h b/grbl/config.h
index bffc41fbc..b8dd9e10b 100644
--- a/grbl/config.h
+++ b/grbl/config.h
@@ -2,6 +2,7 @@
config.h - compile time configuration
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -19,31 +20,162 @@
along with Grbl. If not, see .
*/
-// This file contains compile-time configurations for Grbl's internal system. For the most part,
-// users will not need to directly modify these, but they are here for specific needs, i.e.
+// This file contains compile-time configurations for Grbl's internal system.
+// This file is used to define the number of axix and their names,
+// define homing sequences or specific needs, i.e.
// performance tuning or adjusting to non-typical machines.
// IMPORTANT: Any changes here requires a full re-compiling of the source code to propagate them.
#ifndef config_h
#define config_h
+
#include "grbl.h" // For Arduino IDE compatibility.
+// Serial baud rate
+#define BAUD_RATE 115200
// 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.
// If doing so, simply comment out these two defines and see instructions below.
#define DEFAULTS_GENERIC
-#define CPU_MAP_2560_INITIAL
+#define CPU_MAP_2560_RAMPS_BOARD
+
+//----------------------------------------------------------------------
+// Axis definitions :
+//----------------------------------------------------------------------
+// IMPORTANT: When changing the axis definitions (axis numbers N_AXIS,
+// linears axis number N_AXIS_LINEAR or axes names AXIS_*_NAME,
+// don't forget to issue the reset factory defaults Grbl command: $RST=*
+// if you forget the $RST=* command after change, Grbl may have
+// unpredictable behavior!
+//----------------------------------------------------------------------
+
+#define N_AXIS 5 // Number of axes (3 to 6)
+#define N_AXIS_LINEAR 3 // Number of linears axis, must be <= N_AXIS
+
+// Axis indexing and names
+#define AXIS_1 0 // Axis indexing value. Must start with 0 and be continuous.
+#define AXIS_1_NAME 'X' // Axis names must be in X, Y, Z, A, B, C, U, V, W, D, E & H.
+#define AXIS_2 1
+#define AXIS_2_NAME 'Y'
+#define AXIS_3 2
+#define AXIS_3_NAME 'Z'
+#if N_AXIS <3
+ #error "N_AXIS must be >= 3. N_AXIS < 3 is not implemented."
+#endif
+#if N_AXIS > 3
+ #define AXIS_4 3
+ #define AXIS_4_NAME 'A' // Letter of axis number 4
+#endif
+#if N_AXIS > 4
+ #define AXIS_5 4
+ #define AXIS_5_NAME 'B' // Letter of axis number 5
+#endif
+#if N_AXIS > 5
+ #define AXIS_6 5
+ #define AXIS_6_NAME 'C' // Letter of axis number 6
+#endif
+#if N_AXIS > 6
+ #error "N_AXIS must be <= 6. N_AXIS > 6 is not implemented."
+#endif
-// To use with RAMPS 1.4 Board, comment out the above defines and uncomment the next two defines
-//#define DEFAULTS_RAMPS_BOARD
-//#define CPU_MAP_2560_RAMPS_BOARD
+// Renaming axis doesn't change their number. By default, the status report give axis values in
+// the order of their number. Some graphical interface are not able to affect axis values reported
+// by Grbl to the correct axis name.
+// Uncomment to enable sorting of axis values by axis_names rather than by axis number. Default disabled.
+// If this option is enabled, the sorting order will be X, Y, Z, U, V, W, A, B, C, D, E & H
+// as defined below.
+//#define SORT_REPORT_BY_AXIS_NAME
+//#define AXIS_NAME_SORT_ORDER {'X', 'Y', 'Z', 'U', 'V', 'W', 'A', 'B', 'C', 'D', 'E', 'H'}
+
+#ifdef SORT_REPORT_BY_AXIS_NAME
+ #ifndef AXIS_NAME_SORT_ORDER
+ #error You must define AXIS_NAME_SORT_ORDER to use SORT_REPORT_BY_AXIS_NAME
+ #endif
+#endif
+
+// By default, Grbl report all values of each axis. When cloning axis with more than one axis with
+// the same name, Grbl reports the values several times for the same axis_name if it is cloned.
+// Uncomment to enable report of axis values only one time by axis_names in case of clones axis.
+//#define REPORT_VALUE_FOR_AXIS_NAME_ONCE
+
+#ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ #ifndef SORT_REPORT_BY_AXIS_NAME
+ #error You must define SORT_REPORT_BY_AXIS_NAME to use REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ #endif
+#endif
+
+//----------------------------------------------------------------------
+// End of axis definitions :
+//----------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------
+// Spindle, laser and other PWM output
+//----------------------------------------------------------------------
+// Chose the spindle pin output :
+// SPINDLE_PWM_ON_D8 => 0-12v 16 bits PWM on RAMPS D8 (default)
+// SPINDLE_PWM_ON_D9 => 0-12v 8 bits PWM on RAMPS D9
+// SPINDLE_PWM_ON_D6 => 0-5v 8bits PWM on RAMPS Servo 2 signal (Mega 2560 D6)
+// Uncomment the line which correspond to your hardware
+#define SPINDLE_PWM_ON_D8
+//#define SPINDLE_PWM_ON_D6
+//#define SPINDLE_PWM_ON_D9
+
+// Spindle PWM signal inversion:
+// In case of particular electronics, it may be necessary to invert the values
+// of the PWM signal of the spindle. For example, if the minimum spindle
+// rpm is 1 and maximum is 1000, M3S250 will output 75% instead of 25% and
+// M3S750 will output 25% instead of 75%. Disabled by default
+//#define INVERT_SPINDLE_PWM_VALUES
+
+// Use different spindle output pin in laser mode:
+// Spindle or laser tools do not have the same hardware specifications.
+// When using both spindle and laser on the same machine it will be useful
+// to have spindle and laser on diffrents pins which can deliver the
+// differents outputs nedded.
+//----------------------------------------------------------------------
+// ! IMPORTANT: When changing the SEPARATE_SPINDLE_LASER_PIN compil option,
+// don't forget to issue the reset factory defaults Grbl command: $RST=*
+// if you forget the $RST=* command after change, Grbl may have
+// unpredictable behavior!
+//----------------------------------------------------------------------
+// Uncomment the next line to enable this functionality (default disabled):
+//#define SEPARATE_SPINDLE_LASER_PIN
+
+#ifdef SEPARATE_SPINDLE_LASER_PIN
+ // Laser PWM can be on D6 (default) or on D8 or D9.
+ #define LASER_PWM_ON_D6
+ //#define LASER_PWM_ON_D8
+ //#define LASER_PWM_ON_D9
+#endif
+
+// Use output PWM drived by GCode command M67(Analog Output,Synchronized)
+// or GCode command M68(Analog Output, Immediate).
+//----------------------------------------------------------------------
+// ! IMPORTANT: When changing the USE_OUTPUT_PWM compil option,
+// don't forget to issue the reset factory defaults Grbl command: $RST=*
+// if you forget the $RST=* command after change, Grbl may have
+// unpredictable behavior!
+//----------------------------------------------------------------------
+// Uncomment the next line to enable the use of M67/M68 PWM output (Disabled by default).
+//#define USE_OUTPUT_PWM
+
+#ifdef USE_OUTPUT_PWM
+ // Optional PWM can be on D9 (default) or on D8 or D6.
+ // Warning ! Optional can't use the same timer than the spindle or the laser pin
+ // For more information about this, see the comment of the relevant section in cpu_map.h
+ #define OUTPUT_PWM_ON_D9
+ //#define OUTPUT_PWM_ON_D8
+ //#define OUTPUT_PWM_ON_D6
+#endif
+
+//----------------------------------------------------------------------
+// End of spindle and other PWM output
+//----------------------------------------------------------------------
-// Serial baud rate
-// #define BAUD_RATE 230400
-#define BAUD_RATE 115200
// Define realtime command special characters. These characters are 'picked-off' directly from the
// serial read data stream and are not passed to the grbl line execution parser. Select characters
@@ -106,32 +238,50 @@
// 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.
-#ifdef DEFAULTS_RAMPS_BOARD
- #define HOMING_CYCLE_0 (1<.
*/
-/* The cpu_map.h files serve as a central pin mapping selection file for different
- processor types or alternative pin layouts. This version of Grbl supports only the
+/* The cpu_map.h files serve as a central pin mapping selection file for different
+ processor types or alternative pin layouts. This version of Grbl supports only the
Arduino Mega2560. */
#ifndef cpu_map_h
#define cpu_map_h
-
-#ifdef CPU_MAP_2560_INITIAL // (Arduino Mega 2560) Working @EliteEng
-
- // Serial port interrupt vectors
- #define SERIAL_RX USART0_RX_vect
- #define SERIAL_UDRE USART0_UDRE_vect
-
- // Define step pulse output pins. NOTE: All step bit pins must be on the same port.
- #define STEP_DDR DDRA
- #define STEP_PORT PORTA
- #define STEP_PIN PINA
- #define X_STEP_BIT 2 // MEGA2560 Digital Pin 24
- #define Y_STEP_BIT 3 // MEGA2560 Digital Pin 25
- #define Z_STEP_BIT 4 // MEGA2560 Digital Pin 26
- #define STEP_MASK ((1< 3
+ #define STEP_PORT_3 A // Axis number 4 (Ramps E0)
+ #endif
+ #if N_AXIS > 4
+ #define STEP_PORT_4 C // Axis number 5 (Ramps E1)
+ #endif
+ #if N_AXIS > 5
+ #define STEP_PORT_5 L // Axis number 6 (Ramps Aux-3 D49)
+ #endif
#define STEP_BIT_0 0 // X Step - Pin A0
#define STEP_BIT_1 6 // Y Step - Pin A6
#define STEP_BIT_2 3 // Z Step - Pin D46
+ #if N_AXIS > 3
+ #define STEP_BIT_3 4 // Axis number 4 Step - Pin D26
+ #endif
+ #if N_AXIS > 4
+ #define STEP_BIT_4 1 // Axis number 5 Step - Pin D36
+ #endif
+ #if N_AXIS > 5
+ #define STEP_BIT_5 0 // Axis number 6 Step - Pin D49
+ #endif
#define _STEP_BIT(i) STEP_BIT_##i
#define STEP_BIT(i) _STEP_BIT(i)
#define STEP_DDR(i) _DDR(STEP_PORT_##i)
@@ -166,9 +78,27 @@
#define DIRECTION_PORT_0 F
#define DIRECTION_PORT_1 F
#define DIRECTION_PORT_2 L
+ #if N_AXIS > 3
+ #define DIRECTION_PORT_3 A // Axis number 4 (Ramps E0)
+ #endif
+ #if N_AXIS > 4
+ #define DIRECTION_PORT_4 C // Axis number 5 (Ramps E1)
+ #endif
+ #if N_AXIS > 5
+ #define DIRECTION_PORT_5 B // Axis number 6 (Ramps Aux-3 D51)
+ #endif
#define DIRECTION_BIT_0 1 // X Dir - Pin A1
#define DIRECTION_BIT_1 7 // Y Dir - Pin A7
#define DIRECTION_BIT_2 1 // Z Dir - Pin D48
+ #if N_AXIS > 3
+ #define DIRECTION_BIT_3 6 // Axis number 4 Step - Pin D28
+ #endif
+ #if N_AXIS > 4
+ #define DIRECTION_BIT_4 3 // Axis number 5 Step - Pin D34
+ #endif
+ #if N_AXIS > 5
+ #define DIRECTION_BIT_5 2 // Axis number 6 Step - Pin D51
+ #endif
#define _DIRECTION_BIT(i) DIRECTION_BIT_##i
#define DIRECTION_BIT(i) _DIRECTION_BIT(i)
#define DIRECTION_DDR(i) _DDR(DIRECTION_PORT_##i)
@@ -180,21 +110,57 @@
#define STEPPER_DISABLE_PORT_0 D
#define STEPPER_DISABLE_PORT_1 F
#define STEPPER_DISABLE_PORT_2 K
+ #if N_AXIS > 3
+ #define STEPPER_DISABLE_PORT_3 A // Axis number 4 (Ramps E0)
+ #endif
+ #if N_AXIS > 4
+ #define STEPPER_DISABLE_PORT_4 C // Axis number 5 (Ramps E1)
+ #endif
+ #if N_AXIS > 5
+ #define STEPPER_DISABLE_PORT_5 B // Axis number 5 (Ramps Aux-3 D53)
+ #endif
#define STEPPER_DISABLE_BIT_0 7 // X Enable - Pin D38
#define STEPPER_DISABLE_BIT_1 2 // Y Enable - Pin A2
#define STEPPER_DISABLE_BIT_2 0 // Z Enable - Pin A8
+ #if N_AXIS > 3
+ #define STEPPER_DISABLE_BIT_3 2 // Axis number 4 Step - Pin D24
+ #endif
+ #if N_AXIS > 4
+ #define STEPPER_DISABLE_BIT_4 7 // Axis number 5 Step - Pin D30
+ #endif
+ #if N_AXIS > 5
+ #define STEPPER_DISABLE_BIT_5 0 // Axis number 5 Step - Pin D53
+ #endif
#define STEPPER_DISABLE_BIT(i) STEPPER_DISABLE_BIT_##i
#define STEPPER_DISABLE_DDR(i) _DDR(STEPPER_DISABLE_PORT_##i)
#define STEPPER_DISABLE_PORT(i) _PORT(STEPPER_DISABLE_PORT_##i)
#define STEPPER_DISABLE_PIN(i) _PIN(STEPPER_DISABLE_PORT_##i)
- // Define homing/hard limit switch input pins and limit interrupt vectors.
+ // Define homing/hard limit switch input pins and limit interrupt vectors.
#define MIN_LIMIT_PORT_0 E
#define MIN_LIMIT_PORT_1 J
#define MIN_LIMIT_PORT_2 D
+ #if N_AXIS > 3
+ #define MIN_LIMIT_PORT_3 L
+ #endif
+ #if N_AXIS > 4
+ #define MIN_LIMIT_PORT_4 L
+ #endif
+ #if N_AXIS > 5
+ #define MIN_LIMIT_PORT_5 F // (Ramps Aux-1 D57)
+ #endif
#define MIN_LIMIT_BIT_0 5 // X Limit Min - Pin D3
#define MIN_LIMIT_BIT_1 1 // Y Limit Min - Pin D14
#define MIN_LIMIT_BIT_2 3 // Z Limit Min - Pin D18
+ #if N_AXIS > 3
+ #define MIN_LIMIT_BIT_3 7 // Axis number 4 : RAMPS AUX2 pin D42
+ #endif
+ #if N_AXIS > 4
+ #define MIN_LIMIT_BIT_4 5 // Axis number 5 : RAMPS AUX2 pin D44
+ #endif
+ #if N_AXIS > 5
+ #define MIN_LIMIT_BIT_5 3 // Axis number 6 : RAMPS AUX2 pin D57
+ #endif
#define _MIN_LIMIT_BIT(i) MIN_LIMIT_BIT_##i
#define MIN_LIMIT_BIT(i) _MIN_LIMIT_BIT(i)
#define MIN_LIMIT_DDR(i) _DDR(MIN_LIMIT_PORT_##i)
@@ -204,28 +170,48 @@
#define MAX_LIMIT_PORT_0 E
#define MAX_LIMIT_PORT_1 J
#define MAX_LIMIT_PORT_2 D
+ #if N_AXIS > 3
+ #define MAX_LIMIT_PORT_3 G
+ #endif
+ #if N_AXIS > 4
+ #define MAX_LIMIT_PORT_4 F
+ #endif
+ #if N_AXIS > 5
+ #define MAX_LIMIT_PORT_5 F // (Ramps Aux-3 D58)
+ #endif
#define MAX_LIMIT_BIT_0 4 // X Limit Max - Pin D2
#define MAX_LIMIT_BIT_1 0 // Y Limit Max - Pin D15
#define MAX_LIMIT_BIT_2 2 // Z Limit Max - Pin D19
+ #if N_AXIS > 3
+ #define MAX_LIMIT_BIT_3 1 // Axis number 4 : RAMPS AUX2 pin D40
+ #endif
+ #if N_AXIS > 4
+ #define MAX_LIMIT_BIT_4 5 // Axis number 5 : RAMPS AUX2 pin D59
+ #endif
+ #if N_AXIS > 5
+ #define MAX_LIMIT_BIT_5 4 // Axis number 6 : RAMPS AUX2 pin D58
+ #endif
#define _MAX_LIMIT_BIT(i) MAX_LIMIT_BIT_##i
#define MAX_LIMIT_BIT(i) _MAX_LIMIT_BIT(i)
#define MAX_LIMIT_DDR(i) _DDR(MAX_LIMIT_PORT_##i)
#define MAX_LIMIT_PORT(i) _PORT(MAX_LIMIT_PORT_##i)
#define MAX_LIMIT_PIN(i) _PIN(MAX_LIMIT_PORT_##i)
- // #define LIMIT_INT PCIE0 // Pin change interrupt enable pin
- // #define LIMIT_INT_vect PCINT0_vect
- // #define LIMIT_PCMSK PCMSK0 // Pin change interrupt register
- // #define LIMIT_MASK ((1< Timer0 is used by stepper.c
+ // TIMER1 (controls pin D12, D11); => Timer1 is used by stepper.c
+ // TIMER2 (controls pin D10, D9); => Timer2 is used by analog output or spindle PWM on D9
+ // TIMER3 (controls pin D5, D3, D2); => Timer3 is used by sleep.c
+ // TIMER4 (controls pin D8, D7, D6); => Timer4 is used by analog output or spindle PWM on D8 or D6
+ // TIMER5 (controls pin D46, D45, D44); => Timer5 is unused by grbl-Mega-5X. It's possible to add
+ // PWM capability to ports D44 (RAMPS AUX-2), D45 (RAMPS AUX-4).
+ // D46 is not available for PWM because it's used by Z step.
+ // Arduino pin number and the corresponding register for controlling the duty cycle :
+ // Pin Register
+ // 2 OCR3B
+ // 3 OCR3C
+ // 4 OCR4C
+ // 5 OCR3A
+ // 6 OCR4A
+ // 7 OCR4B
+ // 8 OCR4C
+ // 9 OCR2B
+ // 10 OCR2A
+ // 11 OCR1A
+ // 12 OCR1B
+ // 13 OCR0A
+ // 44 OCR5C
+ // 45 OCR5B
+ // 46 OCR5A
+
+ #if defined(SPINDLE_PWM_ON_D8)
+
+ // Set Timer up to use TIMER4B which is attached to Digital Pin 8 - Ramps 1.4 12v output with heat sink
+ #define SPINDLE_PWM_MAX_VALUE 1024.0 // Translates to about 1.9 kHz PWM frequency at 1/8 prescaler
+ #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)
+
+ //Control Digital Pin 8
+ #define SPINDLE_TCCRA_REGISTER TCCR4A
+ #define SPINDLE_TCCRB_REGISTER TCCR4B
+ #define SPINDLE_OCR_REGISTER OCR4C
+ #define SPINDLE_COMB_BIT COM4C1
+
+ // 1/8 Prescaler, 16-bit Fast PWM mode
+ #define SPINDLE_TCCRA_INIT_MASK ((1< 3
+ #if AXIS_4_NAME != AXIS_1_NAME && AXIS_4_NAME != AXIS_2_NAME && AXIS_4_NAME != AXIS_3_NAME
+ #define DEFAULT_AXIS4_STEPS_PER_UNIT 8.888889 // Direct drive : (200 pas par tours * 1/16 microsteps)/360°
+ #define DEFAULT_AXIS4_MAX_RATE 1440 // °/mn
+ #define DEFAULT_AXIS4_ACCELERATION (50.0*60*60) // 100*60*60 mm/min^2 = 100 mm/sec^2
+ #define DEFAULT_AXIS4_MAX_TRAVEL 360.0 // °
+ #elif AXIS_4_NAME == AXIS_1_NAME
+ #define DEFAULT_AXIS4_STEPS_PER_UNIT DEFAULT_AXIS1_STEPS_PER_UNIT
+ #define DEFAULT_AXIS4_MAX_RATE DEFAULT_AXIS1_MAX_RATE
+ #define DEFAULT_AXIS4_ACCELERATION DEFAULT_AXIS1_ACCELERATION
+ #define DEFAULT_AXIS4_MAX_TRAVEL DEFAULT_AXIS1_MAX_TRAVEL
+ #elif AXIS_4_NAME == AXIS_2_NAME
+ #define DEFAULT_AXIS4_STEPS_PER_UNIT DEFAULT_AXIS2_STEPS_PER_UNIT
+ #define DEFAULT_AXIS4_MAX_RATE DEFAULT_AXIS2_MAX_RATE
+ #define DEFAULT_AXIS4_ACCELERATION DEFAULT_AXIS2_ACCELERATION
+ #define DEFAULT_AXIS4_MAX_TRAVEL DEFAULT_AXIS2_MAX_TRAVEL
+ #else
+ #define DEFAULT_AXIS4_STEPS_PER_UNIT DEFAULT_AXIS3_STEPS_PER_UNIT
+ #define DEFAULT_AXIS4_MAX_RATE DEFAULT_AXIS3_MAX_RATE
+ #define DEFAULT_AXIS4_ACCELERATION DEFAULT_AXIS3_ACCELERATION
+ #define DEFAULT_AXIS4_MAX_TRAVEL DEFAULT_AXIS3_MAX_TRAVEL
+ #endif
+ #endif
+ #if N_AXIS > 4
+ #if AXIS_5_NAME != AXIS_1_NAME && AXIS_5_NAME != AXIS_2_NAME && AXIS_5_NAME != AXIS_3_NAME && \
+ AXIS_5_NAME != AXIS_4_NAME
+ #define DEFAULT_AXIS5_STEPS_PER_UNIT 8.888889 // Direct drive : (200 pas par tours * 1/16 microsteps)/360°
+ #define DEFAULT_AXIS5_MAX_RATE 1440 // °/mn
+ #define DEFAULT_AXIS5_ACCELERATION (50.0*60*60) // 100*60*60 mm/min^2 = 100 mm/sec^2
+ #define DEFAULT_AXIS5_MAX_TRAVEL 180.0 // °
+ #elif AXIS_5_NAME == AXIS_1_NAME
+ #define DEFAULT_AXIS5_STEPS_PER_UNIT DEFAULT_AXIS1_STEPS_PER_UNIT
+ #define DEFAULT_AXIS5_MAX_RATE DEFAULT_AXIS1_MAX_RATE
+ #define DEFAULT_AXIS5_ACCELERATION DEFAULT_AXIS1_ACCELERATION
+ #define DEFAULT_AXIS5_MAX_TRAVEL DEFAULT_AXIS1_MAX_TRAVEL
+ #elif AXIS_5_NAME == AXIS_2_NAME
+ #define DEFAULT_AXIS5_STEPS_PER_UNIT DEFAULT_AXIS2_STEPS_PER_UNIT
+ #define DEFAULT_AXIS5_MAX_RATE DEFAULT_AXIS2_MAX_RATE
+ #define DEFAULT_AXIS5_ACCELERATION DEFAULT_AXIS2_ACCELERATION
+ #define DEFAULT_AXIS5_MAX_TRAVEL DEFAULT_AXIS2_MAX_TRAVEL
+ #elif AXIS_5_NAME == AXIS_3_NAME
+ #define DEFAULT_AXIS5_STEPS_PER_UNIT DEFAULT_AXIS3_STEPS_PER_UNIT
+ #define DEFAULT_AXIS5_MAX_RATE DEFAULT_AXIS3_MAX_RATE
+ #define DEFAULT_AXIS5_ACCELERATION DEFAULT_AXIS3_ACCELERATION
+ #define DEFAULT_AXIS5_MAX_TRAVEL DEFAULT_AXIS3_MAX_TRAVEL
+ #else
+ #define DEFAULT_AXIS5_STEPS_PER_UNIT DEFAULT_AXIS4_STEPS_PER_UNIT
+ #define DEFAULT_AXIS5_MAX_RATE DEFAULT_AXIS4_MAX_RATE
+ #define DEFAULT_AXIS5_ACCELERATION DEFAULT_AXIS4_ACCELERATION
+ #define DEFAULT_AXIS5_MAX_TRAVEL DEFAULT_AXIS4_MAX_TRAVEL
+ #endif
+ #endif
+ #if N_AXIS > 5
+ #if AXIS_6_NAME != AXIS_1_NAME && AXIS_6_NAME != AXIS_2_NAME && \
+ AXIS_6_NAME != AXIS_3_NAME && AXIS_6_NAME != AXIS_4_NAME && AXIS_6_NAME != AXIS_5_NAME
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT 8.888889 // Direct drive : (200 pas par tours * 1/16 microsteps)/360°
+ #define DEFAULT_AXIS6_MAX_RATE 1440 // °/mn
+ #define DEFAULT_AXIS6_ACCELERATION (50.0*60*60) // 100*60*60 mm/min^2 = 100 mm/sec^2
+ #define DEFAULT_AXIS6_MAX_TRAVEL 180.0 // °
+ #elif AXIS_6_NAME == AXIS_1_NAME
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT DEFAULT_AXIS1_STEPS_PER_UNIT
+ #define DEFAULT_AXIS6_MAX_RATE DEFAULT_AXIS1_MAX_RATE
+ #define DEFAULT_AXIS6_ACCELERATION DEFAULT_AXIS1_ACCELERATION
+ #define DEFAULT_AXIS6_MAX_TRAVEL DEFAULT_AXIS1_MAX_TRAVEL
+ #elif AXIS_6_NAME == AXIS_2_NAME
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT DEFAULT_AXIS2_STEPS_PER_UNIT
+ #define DEFAULT_AXIS6_MAX_RATE DEFAULT_AXIS2_MAX_RATE
+ #define DEFAULT_AXIS6_ACCELERATION DEFAULT_AXIS2_ACCELERATION
+ #define DEFAULT_AXIS6_MAX_TRAVEL DEFAULT_AXIS2_MAX_TRAVEL
+ #elif AXIS_6_NAME == AXIS_3_NAME
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT DEFAULT_AXIS3_STEPS_PER_UNIT
+ #define DEFAULT_AXIS6_MAX_RATE DEFAULT_AXIS3_MAX_RATE
+ #define DEFAULT_AXIS6_ACCELERATION DEFAULT_AXIS3_ACCELERATION
+ #define DEFAULT_AXIS6_MAX_TRAVEL DEFAULT_AXIS3_MAX_TRAVEL
+ #elif AXIS_6_NAME == AXIS_4_NAME
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT DEFAULT_AXIS4_STEPS_PER_UNIT
+ #define DEFAULT_AXIS6_MAX_RATE DEFAULT_AXIS4_MAX_RATE
+ #define DEFAULT_AXIS6_ACCELERATION DEFAULT_AXIS4_ACCELERATION
+ #define DEFAULT_AXIS6_MAX_TRAVEL DEFAULT_AXIS4_MAX_TRAVEL
+ #else
+ #define DEFAULT_AXIS6_STEPS_PER_UNIT DEFAULT_AXIS5_STEPS_PER_UNIT
+ #define DEFAULT_AXIS6_MAX_RATE DEFAULT_AXIS5_MAX_RATE
+ #define DEFAULT_AXIS6_ACCELERATION DEFAULT_AXIS5_ACCELERATION
+ #define DEFAULT_AXIS6_MAX_TRAVEL DEFAULT_AXIS5_MAX_TRAVEL
+ #endif
+ #endif
+ #define DEFAULT_SPINDLE_RPM_MAX 12000 // rpm
+ #define DEFAULT_SPINDLE_RPM_MIN 550.0 // rpm
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ #define DEFAULT_LASER_MAX 100
+ #define DEFAULT_LASER_MIN 1
+ #endif
+ #ifdef USE_OUTPUT_PWM
+ #if defined(OUTPUT_PWM_ON_D9) || defined(OUTPUT_PWM_ON_D8)
+ #define DEFAULT_OUTPUT_MAX 12.0 // volts
+ #define DEFAULT_OUTPUT_MIN 1.4 // volts
+ #else // (OUTPUT_PWM_ON_D6)
+ #define DEFAULT_OUTPUT_MAX 5.0 // volts
+ #define DEFAULT_OUTPUT_MIN 0.04 // volts
+ #endif
+ #endif
+ #define DEFAULT_STEP_PULSE_MICROSECONDS 10
+ #define DEFAULT_STEPPING_INVERT_MASK 0
+ #define DEFAULT_DIRECTION_INVERT_MASK 0
+ #define DEFAULT_STEPPER_IDLE_LOCK_TIME 254 // msec (0-254, 255 keeps steppers enabled)
+ #define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
+ #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
+ #define DEFAULT_ARC_TOLERANCE 0.002 // mm
+ #define DEFAULT_REPORT_INCHES 0 // false
+ #define DEFAULT_INVERT_ST_ENABLE 0 // false
+ #define DEFAULT_INVERT_LIMIT_PINS 0 // false
+ #define DEFAULT_SOFT_LIMIT_ENABLE 1 // true
+ #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
+ #define DEFAULT_INVERT_PROBE_PIN 0 // false
+ #define DEFAULT_LASER_MODE 0 // false
+ #define DEFAULT_HOMING_ENABLE 1 // true
+ #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
+ #define DEFAULT_HOMING_FEED_RATE 25.0 // mm/min
+ #define DEFAULT_HOMING_SEEK_RATE 250.0 // mm/min
+ #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
+ #define DEFAULT_HOMING_PULLOFF 5.0 // mm
+ #endif
-#ifdef DEFAULTS_OXCNC
- // Grbl settings for OpenBuilds OX CNC Machine
- // http://www.openbuilds.com/builds/openbuilds-ox-cnc-machine.341/
- #define DEFAULT_X_STEPS_PER_MM 26.670
- #define DEFAULT_Y_STEPS_PER_MM 26.670
- #define DEFAULT_Z_STEPS_PER_MM 50
- #define DEFAULT_X_MAX_RATE 500.0 // mm/min
- #define DEFAULT_Y_MAX_RATE 500.0 // mm/min
- #define DEFAULT_Z_MAX_RATE 500.0 // mm/min
- #define DEFAULT_X_ACCELERATION (10.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_Y_ACCELERATION (10.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_Z_ACCELERATION (10.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_X_MAX_TRAVEL 500.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_Y_MAX_TRAVEL 750.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_Z_MAX_TRAVEL 80.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
- #define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
- #define DEFAULT_STEP_PULSE_MICROSECONDS 10
- #define DEFAULT_STEPPING_INVERT_MASK 0
- #define DEFAULT_DIRECTION_INVERT_MASK 0
- #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
- #define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
- #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
- #define DEFAULT_ARC_TOLERANCE 0.002 // mm
- #define DEFAULT_REPORT_INCHES 0 // false
- #define DEFAULT_INVERT_ST_ENABLE 0 // false
- #define DEFAULT_INVERT_LIMIT_PINS 0 // false
- #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
- #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
- #define DEFAULT_INVERT_PROBE_PIN 0 // false
- #define DEFAULT_LASER_MODE 0 // false
- #define DEFAULT_HOMING_ENABLE 0 // false
- #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
- #define DEFAULT_HOMING_FEED_RATE 25.0 // mm/min
- #define DEFAULT_HOMING_SEEK_RATE 500.0 // mm/min
- #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
- #define DEFAULT_HOMING_PULLOFF 1.0 // mm
#endif
-
-#ifdef DEFAULTS_SIMULATOR
- // Settings only for Grbl Simulator (www.github.com/grbl/grbl-sim)
- // Grbl generic default settings. Should work across different machines.
- #define DEFAULT_X_STEPS_PER_MM 1000.0
- #define DEFAULT_Y_STEPS_PER_MM 1000.0
- #define DEFAULT_Z_STEPS_PER_MM 1000.0
- #define DEFAULT_X_MAX_RATE 1000.0 // mm/min
- #define DEFAULT_Y_MAX_RATE 1000.0 // mm/min
- #define DEFAULT_Z_MAX_RATE 1000.0 // mm/min
- #define DEFAULT_X_ACCELERATION (100.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_Y_ACCELERATION (100.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_Z_ACCELERATION (100.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
- #define DEFAULT_X_MAX_TRAVEL 1000.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_Y_MAX_TRAVEL 1000.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_Z_MAX_TRAVEL 1000.0 // mm NOTE: Must be a positive value.
- #define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
- #define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
- #define DEFAULT_STEP_PULSE_MICROSECONDS 10
- #define DEFAULT_STEPPING_INVERT_MASK 0
- #define DEFAULT_DIRECTION_INVERT_MASK 0
- #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 // msec (0-254, 255 keeps steppers enabled)
- #define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
- #define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
- #define DEFAULT_ARC_TOLERANCE 0.002 // mm
- #define DEFAULT_REPORT_INCHES 0 // false
- #define DEFAULT_INVERT_ST_ENABLE 0 // false
- #define DEFAULT_INVERT_LIMIT_PINS 0 // false
- #define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
- #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
- #define DEFAULT_INVERT_PROBE_PIN 0 // false
- #define DEFAULT_LASER_MODE 0 // false
- #define DEFAULT_HOMING_ENABLE 0 // false
- #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
- #define DEFAULT_HOMING_FEED_RATE 25.0 // mm/min
- #define DEFAULT_HOMING_SEEK_RATE 500.0 // mm/min
- #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
- #define DEFAULT_HOMING_PULLOFF 1.0 // mm
-#endif
-
-#ifdef DEFAULTS_RAMPS_BOARD
- #define DEFAULT_X_STEPS_PER_MM 80
- #define DEFAULT_Y_STEPS_PER_MM 80
- #define DEFAULT_Z_STEPS_PER_MM 4000
- #define DEFAULT_X_MAX_RATE 18000.0 // mm/min
- #define DEFAULT_Y_MAX_RATE 18000.0 // mm/min
- #define DEFAULT_Z_MAX_RATE 300.0 // mm/min
- #define DEFAULT_X_ACCELERATION 3000
- #define DEFAULT_Y_ACCELERATION 3000
- #define DEFAULT_Z_ACCELERATION 100
- #define DEFAULT_X_MAX_TRAVEL 200.0 // mm
- #define DEFAULT_Y_MAX_TRAVEL 200.0 // mm
- #define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
- #define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
- #define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
- #define DEFAULT_STEP_PULSE_MICROSECONDS 10
- #define DEFAULT_STEPPING_INVERT_MASK 0
- #define DEFAULT_DIRECTION_INVERT_MASK 0
- #define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // msec (0-254, 255 keeps steppers enabled)
- #define DEFAULT_STATUS_REPORT_MASK 1 // MPos enabled
- #define DEFAULT_JUNCTION_DEVIATION 0.02 // mm
- #define DEFAULT_ARC_TOLERANCE 0.002 // mm
- #define DEFAULT_REPORT_INCHES 0 // false
- #define DEFAULT_INVERT_ST_ENABLE 0 // false
- #define DEFAULT_INVERT_LIMIT_PINS 0 // false
- #define DEFAULT_SOFT_LIMIT_ENABLE 1 // true
- #define DEFAULT_HARD_LIMIT_ENABLE 0 // false
- #define DEFAULT_INVERT_PROBE_PIN 0 // false
- #define DEFAULT_LASER_MODE 0 // false
- #define DEFAULT_HOMING_ENABLE 1 // true
- #define DEFAULT_HOMING_DIR_MASK 0 // move positive dir
- #define DEFAULT_HOMING_FEED_RATE 500.0 // mm/min
- #define DEFAULT_HOMING_SEEK_RATE 2000.0 // mm/min
- #define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
- #define DEFAULT_HOMING_PULLOFF 5.0 // mm
-#endif
-
-#endif
\ No newline at end of file
diff --git a/grbl/digital_control.c b/grbl/digital_control.c
new file mode 100644
index 000000000..e6bf9a264
--- /dev/null
+++ b/grbl/digital_control.c
@@ -0,0 +1,226 @@
+/*
+ digital_control.c - digital output M62-M65 control methods
+ Part of Grbl
+
+ Copyright (c) 2017-2022 Gauthier Briere
+
+ Grbl is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Grbl is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grbl. If not, see .
+*/
+
+#include "grbl.h"
+
+
+void digital_init()
+{
+ // Outputs
+ DIGITAL_OUTPUT_DDR_0 |= (1 << DIGITAL_OUTPUT_BIT_0); // Configure as output pin.
+ DIGITAL_OUTPUT_DDR_1 |= (1 << DIGITAL_OUTPUT_BIT_1); // Configure as output pin.
+ DIGITAL_OUTPUT_DDR_2 |= (1 << DIGITAL_OUTPUT_BIT_2); // Configure as output pin.
+ DIGITAL_OUTPUT_DDR_3 |= (1 << DIGITAL_OUTPUT_BIT_3); // Configure as output pin.
+ digital_stop(0x0F);
+ #ifdef USE_DIGITAL_INPUT
+ // Input
+ DIGITAL_INPUT_DDR_0 &= ~(DIGITAL_INPUT_MASK_0); // Configure as input pin
+ DIGITAL_INPUT_DDR_1 &= ~(DIGITAL_INPUT_MASK_1); // Configure as input pin
+ DIGITAL_INPUT_DDR_2 &= ~(DIGITAL_INPUT_MASK_2); // Configure as input pin
+ DIGITAL_INPUT_DDR_3 &= ~(DIGITAL_INPUT_MASK_3); // Configure as input pin
+ #ifdef DISABLE_DIGITAL_INPUT_PIN_PULL_UP
+ DIGITAL_INPUT_PORT_0 &= ~(DIGITAL_INPUT_MASK_0); // Normal low operation. Requires external pull-down.
+ DIGITAL_INPUT_PORT_1 &= ~(DIGITAL_INPUT_MASK_1); // Normal low operation. Requires external pull-down.
+ DIGITAL_INPUT_PORT_2 &= ~(DIGITAL_INPUT_MASK_2); // Normal low operation. Requires external pull-down.
+ DIGITAL_INPUT_PORT_3 &= ~(DIGITAL_INPUT_MASK_3); // Normal low operation. Requires external pull-down.
+ #else
+ DIGITAL_INPUT_PORT_0 |= DIGITAL_INPUT_MASK_0; // Enable internal pull-up resistors. Normal high operation.
+ DIGITAL_INPUT_PORT_1 |= DIGITAL_INPUT_MASK_1; // Enable internal pull-up resistors. Normal high operation.
+ DIGITAL_INPUT_PORT_2 |= DIGITAL_INPUT_MASK_2; // Enable internal pull-up resistors. Normal high operation.
+ DIGITAL_INPUT_PORT_3 |= DIGITAL_INPUT_MASK_3; // Enable internal pull-up resistors. Normal high operation.
+ #endif
+ #endif
+}
+
+
+// Returns current digital output state. Overrides may alter it from programmed state.
+uint8_t digital_get_state()
+{
+ uint8_t digital_state = DIGITAL_OUTPUT_STATE_OFF;
+ // Output status
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_0
+ if (bit_isfalse(DIGITAL_OUTPUT_PORT_0,(1 << DIGITAL_OUTPUT_BIT_0))) {
+ #else
+ if (bit_istrue(DIGITAL_OUTPUT_PORT_0,(1 << DIGITAL_OUTPUT_BIT_0))) {
+ #endif
+ digital_state |= DIGITAL_OUTPUT_STATE_P0;
+ }
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_1
+ if (bit_isfalse(DIGITAL_OUTPUT_PORT_1,(1 << DIGITAL_OUTPUT_BIT_1))) {
+ #else
+ if (bit_istrue(DIGITAL_OUTPUT_PORT_1,(1 << DIGITAL_OUTPUT_BIT_1))) {
+ #endif
+ digital_state |= DIGITAL_OUTPUT_STATE_P1;
+ }
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_2
+ if (bit_isfalse(DIGITAL_OUTPUT_PORT_2,(1 << DIGITAL_OUTPUT_BIT_2))) {
+ #else
+ if (bit_istrue(DIGITAL_OUTPUT_PORT_2,(1 << DIGITAL_OUTPUT_BIT_2))) {
+ #endif
+ digital_state |= DIGITAL_OUTPUT_STATE_P2;
+ }
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_3
+ if (bit_isfalse(DIGITAL_OUTPUT_PORT_3,(1 << DIGITAL_OUTPUT_BIT_3))) {
+ #else
+ if (bit_istrue(DIGITAL_OUTPUT_PORT_3,(1 << DIGITAL_OUTPUT_BIT_3))) {
+ #endif
+ digital_state |= DIGITAL_OUTPUT_STATE_P3;
+ }
+ // Input status
+ #ifdef USE_DIGITAL_INPUT
+ #ifdef INVERT_DIGITAL_INPUT_PIN_0
+ if (DIGITAL_INPUT_PIN_0 & DIGITAL_INPUT_MASK_0) {
+ #else
+ if (!(DIGITAL_INPUT_PIN_0 & DIGITAL_INPUT_MASK_0)) {
+ #endif
+ digital_state |= DIGITAL_INPUT_STATE_P0;
+ }
+ #ifdef INVERT_DIGITAL_INPUT_PIN_1
+ if (DIGITAL_INPUT_PIN_1 & DIGITAL_INPUT_MASK_1) {
+ #else
+ if (!(DIGITAL_INPUT_PIN_1 & DIGITAL_INPUT_MASK_1)) {
+ #endif
+ digital_state |= DIGITAL_INPUT_STATE_P1;
+ }
+ #ifdef INVERT_DIGITAL_INPUT_PIN_2
+ if (DIGITAL_INPUT_PIN_2 & DIGITAL_INPUT_MASK_2) {
+ #else
+ if (!(DIGITAL_INPUT_PIN_2 & DIGITAL_INPUT_MASK_2)) {
+ #endif
+ digital_state |= DIGITAL_INPUT_STATE_P2;
+ }
+ #ifdef INVERT_DIGITAL_INPUT_PIN_3
+ if (DIGITAL_INPUT_PIN_3 & DIGITAL_INPUT_MASK_3) {
+ #else
+ if (!(DIGITAL_INPUT_PIN_3 & DIGITAL_INPUT_MASK_3)) {
+ #endif
+ digital_state |= DIGITAL_INPUT_STATE_P3;
+ }
+ #endif
+ return(digital_state);
+}
+
+
+// Directly called by digital_init(), digital_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.
+// The mode argument is a bit flag wich define which output must be stopped.
+void digital_stop(const uint8_t mode)
+{
+ if (mode & DIGITAL_OUTPUT_STATE_P0) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_0
+ DIGITAL_OUTPUT_PORT_0 |= (1 << DIGITAL_OUTPUT_BIT_0);
+ #else
+ DIGITAL_OUTPUT_PORT_0 &= ~(1 << DIGITAL_OUTPUT_BIT_0);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P1) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_1
+ DIGITAL_OUTPUT_PORT_1 |= (1 << DIGITAL_OUTPUT_BIT_1);
+ #else
+ DIGITAL_OUTPUT_PORT_1 &= ~(1 << DIGITAL_OUTPUT_BIT_1);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P2) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_2
+ DIGITAL_OUTPUT_PORT_2 |= (1 << DIGITAL_OUTPUT_BIT_2);
+ #else
+ DIGITAL_OUTPUT_PORT_2 &= ~(1 << DIGITAL_OUTPUT_BIT_2);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P3) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_3
+ DIGITAL_OUTPUT_PORT_3 |= (1 << DIGITAL_OUTPUT_BIT_3);
+ #else
+ DIGITAL_OUTPUT_PORT_3 &= ~(1 << DIGITAL_OUTPUT_BIT_3);
+ #endif
+ }
+}
+
+
+// Immediately sets digital outputs
+// Also sets a flag to report an update to a digital state.
+void digital_set_state(uint8_t mode)
+{
+ if (sys.abort) { return; } // Block during abort.
+
+ if (mode & DIGITAL_OUTPUT_STATE_P0) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_0
+ DIGITAL_OUTPUT_PORT_0 &= ~(1 << DIGITAL_OUTPUT_BIT_0);
+ #else
+ DIGITAL_OUTPUT_PORT_0 |= (1 << DIGITAL_OUTPUT_BIT_0);
+ #endif
+ } else {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_0
+ DIGITAL_OUTPUT_PORT_0 |= (1 << DIGITAL_OUTPUT_BIT_0);
+ #else
+ DIGITAL_OUTPUT_PORT_0 &= ~(1 << DIGITAL_OUTPUT_BIT_0);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P1) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_1
+ DIGITAL_OUTPUT_PORT_1 &= ~(1 << DIGITAL_OUTPUT_BIT_1);
+ #else
+ DIGITAL_OUTPUT_PORT_1 |= (1 << DIGITAL_OUTPUT_BIT_1);
+ #endif
+ } else {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_1
+ DIGITAL_OUTPUT_PORT_1 |= (1 << DIGITAL_OUTPUT_BIT_1);
+ #else
+ DIGITAL_OUTPUT_PORT_1 &= ~(1 << DIGITAL_OUTPUT_BIT_1);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P2) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_2
+ DIGITAL_OUTPUT_PORT_2 &= ~(1 << DIGITAL_OUTPUT_BIT_2);
+ #else
+ DIGITAL_OUTPUT_PORT_2 |= (1 << DIGITAL_OUTPUT_BIT_2);
+ #endif
+ } else {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_2
+ DIGITAL_OUTPUT_PORT_2 |= (1 << DIGITAL_OUTPUT_BIT_2);
+ #else
+ DIGITAL_OUTPUT_PORT_2 &= ~(1 << DIGITAL_OUTPUT_BIT_2);
+ #endif
+ }
+ if (mode & DIGITAL_OUTPUT_STATE_P3) {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_3
+ DIGITAL_OUTPUT_PORT_3 &= ~(1 << DIGITAL_OUTPUT_BIT_3);
+ #else
+ DIGITAL_OUTPUT_PORT_3 |= (1 << DIGITAL_OUTPUT_BIT_3);
+ #endif
+ } else {
+ #ifdef INVERT_DIGITAL_OUTPUT_PIN_3
+ DIGITAL_OUTPUT_PORT_3 |= (1 << DIGITAL_OUTPUT_BIT_3);
+ #else
+ DIGITAL_OUTPUT_PORT_3 &= ~(1 << DIGITAL_OUTPUT_BIT_3);
+ #endif
+ }
+ sys.report_ovr_counter = 0; // Set to report change immediately
+}
+
+
+// G-code parser entry-point for setting digital state. Forces a planner buffer sync and bails
+// if an abort or check-mode is active.
+void digital_sync(uint8_t mode)
+{
+ if (sys.state == STATE_CHECK_MODE) { return; }
+ protocol_buffer_synchronize(); // Ensure digital turns on when specified in program.
+ digital_set_state(mode);
+}
diff --git a/grbl/digital_control.h b/grbl/digital_control.h
new file mode 100644
index 000000000..cd3d8d83f
--- /dev/null
+++ b/grbl/digital_control.h
@@ -0,0 +1,51 @@
+/*
+ digital_control.h - digital output M62-M65 control methods
+ Part of Grbl
+
+ Copyright (c) 2017-2022 Gauthier Briere
+
+ Grbl is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Grbl is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Grbl. If not, see .
+*/
+
+#ifndef digital_control_h
+#define digital_control_h
+
+#define DIGITAL_OUTPUT_STATE_OFF 0 // Must be zero
+#define DIGITAL_OUTPUT_STATE_P0 bit(0)
+#define DIGITAL_OUTPUT_STATE_P1 bit(1)
+#define DIGITAL_OUTPUT_STATE_P2 bit(2)
+#define DIGITAL_OUTPUT_STATE_P3 bit(3)
+#ifdef USE_DIGITAL_INPUT
+ #define DIGITAL_INPUT_STATE_P0 bit(4)
+ #define DIGITAL_INPUT_STATE_P1 bit(5)
+ #define DIGITAL_INPUT_STATE_P2 bit(6)
+ #define DIGITAL_INPUT_STATE_P3 bit(7)
+#endif
+
+// Initializes digital output control pins.
+void digital_init();
+
+// Returns current digital output state. Overrides may alter it from programmed state.
+uint8_t digital_get_state();
+
+// Immediately disables digital output pins.
+void digital_stop(const uint8_t n);
+
+// Sets the digital output pins according to state specified.
+void digital_set_state(uint8_t mode);
+
+// G-code parser entry-point for setting digital output states. Checks for and executes additional conditions.
+void digital_sync(uint8_t mode);
+
+#endif
diff --git a/grbl/examples/grblUpload/grblUpload.ino b/grbl/examples/grblUpload/grblUpload.ino
index 581b6b3d7..f1ebc2ab9 100644
--- a/grbl/examples/grblUpload/grblUpload.ino
+++ b/grbl/examples/grblUpload/grblUpload.ino
@@ -1,12 +1,13 @@
/***********************************************************************
-This sketch compiles and uploads Grbl to your 328p-based Arduino!
+This sketch compiles and uploads Grbl to your Mega2560 Arduino board!
To use:
- First make sure you have imported Grbl source code into your Arduino
- IDE. There are details on our Github website on how to do this.
+ IDE. See more details on the Github wiki page of grbl-Mega-5X:
+ https://github.com/fra589/grbl-Mega-5X/wiki/Compiling-grbl-Mega-5X
- Select your Arduino Board and Serial Port in the Tools drop-down menu.
- NOTE: Grbl only officially supports 328p-based Arduinos, like the Uno.
+ NOTE: grbl-Mega-5X only officially supports Mega2560 Arduino boards.
Using other boards will likely not work!
- Then just click 'Upload'. That's it!
diff --git a/grbl/gcode.c b/grbl/gcode.c
index 3b323700e..86f0b65e3 100644
--- a/grbl/gcode.c
+++ b/grbl/gcode.c
@@ -2,6 +2,7 @@
gcode.c - rs274/ngc parser.
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -25,7 +26,8 @@
// arbitrary value, and some GUIs may require more. So we increased it based on a max safe
// value when converting a float (7.2 digit precision)s to an integer.
#define MAX_LINE_NUMBER 10000000
-#define MAX_TOOL_NUMBER 255 // Limited by max unsigned 8-bit value
+#define MAX_TOOL_NUMBER 255 // Limited by max unsigned 8-bit value
+#define MAX_DIGITAL_OUTPUT 3 // 4 defined digital IO output (0 to 3)
#define AXIS_COMMAND_NONE 0
#define AXIS_COMMAND_NON_MODAL 1
@@ -75,17 +77,35 @@ uint8_t gc_execute_line(char *line)
memset(&gc_block, 0, sizeof(parser_block_t)); // Initialize the parser block struct.
memcpy(&gc_block.modal,&gc_state.modal,sizeof(gc_modal_t)); // Copy current modes
+ // Keep track of current tool number (set tool number modal)
+ gc_block.values.t = gc_state.tool;
+
uint8_t axis_command = AXIS_COMMAND_NONE;
uint8_t axis_0, axis_1, axis_linear;
+ uint8_t axis_a, axis_b, axis_c;
+ uint8_t axis_u, axis_v, axis_w;
+ uint8_t axis_d, axis_e, axis_h;
+ uint8_t axis_0_mask = 0;
+ uint8_t axis_1_mask = 0;
+ uint8_t axis_linear_mask = 0;
+ uint8_t axis_a_mask = 0;
+ uint8_t axis_b_mask = 0;
+ uint8_t axis_c_mask = 0;
+ uint8_t axis_u_mask = 0;
+ uint8_t axis_v_mask = 0;
+ uint8_t axis_w_mask = 0;
+ uint8_t axis_d_mask = 0;
+ uint8_t axis_e_mask = 0;
+ uint8_t axis_h_mask = 0;
uint8_t coord_select = 0; // Tracks G10 P coordinate selection for execution
// Initialize bitflag tracking variables for axis indices compatible operations.
- uint8_t axis_words = 0; // XYZ tracking
+ uint32_t axis_dwords = 0; // XYZ tracking
uint8_t ijk_words = 0; // IJK tracking
// Initialize command and value words and parser flags variables.
- uint16_t command_words = 0; // Tracks G and M command words. Also used for modal group violations.
- uint16_t value_words = 0; // Tracks value words.
+ uint32_t command_dwords = 0; // Tracks G and M command words. Also used for modal group violations.
+ uint32_t value_dwords = 0; // Tracks value words.
uint8_t gc_parser_flags = GC_PARSER_NONE;
// Determine if the line is a jogging motion or a normal g-code block.
@@ -103,7 +123,7 @@ uint8_t gc_execute_line(char *line)
perform initial error-checks for command word modal group violations, for any repeated
words, and for negative values set for the value words F, N, P, T, and S. */
- uint8_t word_bit; // Bit-value for assigning tracking variables
+ uint32_t dword_bit; // Bit-value for assigning tracking variables
uint8_t char_counter;
char letter;
float value;
@@ -150,13 +170,13 @@ uint8_t gc_execute_line(char *line)
}
// No break. Continues to next line.
case 4: case 53:
- word_bit = MODAL_GROUP_G0;
+ dword_bit = MODAL_GROUP_G0;
gc_block.non_modal_command = int_value;
if ((int_value == 28) || (int_value == 30) || (int_value == 92)) {
if (!((mantissa == 0) || (mantissa == 10))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); }
gc_block.non_modal_command += mantissa;
mantissa = 0; // Set to zero to indicate valid non-integer G command.
- }
+ }
break;
case 0: case 1: case 2: case 3: case 38:
// Check for G0/1/2/3/38 being called with G10/28/30/92 on same block.
@@ -165,7 +185,7 @@ uint8_t gc_execute_line(char *line)
axis_command = AXIS_COMMAND_MOTION_MODE;
// No break. Continues to next line.
case 80:
- word_bit = MODAL_GROUP_G1;
+ dword_bit = MODAL_GROUP_G1;
gc_block.modal.motion = int_value;
if (int_value == 38){
if (!((mantissa == 20) || (mantissa == 30) || (mantissa == 40) || (mantissa == 50))) {
@@ -173,39 +193,39 @@ uint8_t gc_execute_line(char *line)
}
gc_block.modal.motion += (mantissa/10)+100;
mantissa = 0; // Set to zero to indicate valid non-integer G command.
- }
+ }
break;
case 17: case 18: case 19:
- word_bit = MODAL_GROUP_G2;
+ dword_bit = MODAL_GROUP_G2;
gc_block.modal.plane_select = int_value - 17;
break;
case 90: case 91:
if (mantissa == 0) {
- word_bit = MODAL_GROUP_G3;
+ dword_bit = MODAL_GROUP_G3;
gc_block.modal.distance = int_value - 90;
} else {
- word_bit = MODAL_GROUP_G4;
+ dword_bit = MODAL_GROUP_G4;
if ((mantissa != 10) || (int_value == 90)) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G90.1 not supported]
mantissa = 0; // Set to zero to indicate valid non-integer G command.
// Otherwise, arc IJK incremental mode is default. G91.1 does nothing.
}
break;
case 93: case 94:
- word_bit = MODAL_GROUP_G5;
+ dword_bit = MODAL_GROUP_G5;
gc_block.modal.feed_rate = 94 - int_value;
break;
case 20: case 21:
- word_bit = MODAL_GROUP_G6;
+ dword_bit = MODAL_GROUP_G6;
gc_block.modal.units = 21 - int_value;
break;
case 40:
- word_bit = MODAL_GROUP_G7;
+ dword_bit = MODAL_GROUP_G7;
// NOTE: Not required since cutter radius compensation is always disabled. Only here
// to support G40 commands that often appear in g-code program headers to setup defaults.
// gc_block.modal.cutter_comp = CUTTER_COMP_DISABLE; // G40
break;
case 43: case 49:
- word_bit = MODAL_GROUP_G8;
+ dword_bit = MODAL_GROUP_G8;
// NOTE: The NIST g-code standard vaguely states that when a tool length offset is changed,
// there cannot be any axis motion or coordinate offsets updated. Meaning G43, G43.1, and G49
// all are explicit axis commands, regardless if they require axis words or not.
@@ -220,11 +240,11 @@ uint8_t gc_execute_line(char *line)
break;
case 54: case 55: case 56: case 57: case 58: case 59:
// NOTE: G59.x are not supported. (But their int_values would be 60, 61, and 62.)
- word_bit = MODAL_GROUP_G12;
+ dword_bit = MODAL_GROUP_G12;
gc_block.modal.coord_select = int_value - 54; // Shift to array indexing.
break;
case 61:
- word_bit = MODAL_GROUP_G13;
+ dword_bit = MODAL_GROUP_G13;
if (mantissa != 0) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G61.1 not supported]
// gc_block.modal.control = CONTROL_MODE_EXACT_PATH; // G61
break;
@@ -232,9 +252,9 @@ uint8_t gc_execute_line(char *line)
}
if (mantissa > 0) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); } // [Unsupported or invalid Gxx.x command]
// Check for more than one command per modal group violations in the current block
- // NOTE: Variable 'word_bit' is always assigned, if the command is valid.
- if ( bit_istrue(command_words,bit(word_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); }
- command_words |= bit(word_bit);
+ // NOTE: Variable 'dword_bit' is always assigned, if the command is valid.
+ if ( bit_istrue(command_dwords,dwbit(dword_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); }
+ command_dwords |= dwbit(dword_bit);
break;
case 'M':
@@ -243,7 +263,7 @@ uint8_t gc_execute_line(char *line)
if (mantissa > 0) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); } // [No Mxx.x commands]
switch(int_value) {
case 0: case 1: case 2: case 30:
- word_bit = MODAL_GROUP_M4;
+ dword_bit = MODAL_GROUP_M4;
switch(int_value) {
case 0: gc_block.modal.program_flow = PROGRAM_FLOW_PAUSED; break; // Program pause
case 1: break; // Optional stop not supported. Ignore.
@@ -251,34 +271,46 @@ uint8_t gc_execute_line(char *line)
}
break;
case 3: case 4: case 5:
- word_bit = MODAL_GROUP_M7;
+ dword_bit = MODAL_GROUP_M7;
switch(int_value) {
case 3: gc_block.modal.spindle = SPINDLE_ENABLE_CW; break;
case 4: gc_block.modal.spindle = SPINDLE_ENABLE_CCW; break;
case 5: gc_block.modal.spindle = SPINDLE_DISABLE; break;
}
- break;
+ break;
case 7: case 8: case 9:
- word_bit = MODAL_GROUP_M8;
+ dword_bit = MODAL_GROUP_M8;
switch(int_value) {
- case 7: gc_block.modal.coolant = COOLANT_MIST_ENABLE; break;
- case 8: gc_block.modal.coolant = COOLANT_FLOOD_ENABLE; break;
- case 9: gc_block.modal.coolant = COOLANT_DISABLE; break;
+ case 7: gc_block.modal.coolant |= COOLANT_MIST_ENABLE; break;
+ case 8: gc_block.modal.coolant |= COOLANT_FLOOD_ENABLE; break;
+ case 9: gc_block.modal.coolant = COOLANT_DISABLE; break; // M9 disables both M7 and M8.
}
break;
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
case 56:
- word_bit = MODAL_GROUP_M9;
+ dword_bit = MODAL_GROUP_M9;
gc_block.modal.override = OVERRIDE_PARKING_MOTION;
break;
#endif
+ case 62: case 63: case 64: case 65:
+ // M62, M63, M64, M65
+ dword_bit = MODAL_GROUP_M10;
+ gc_block.non_modal_command = int_value;
+ break;
+ #ifdef USE_OUTPUT_PWM
+ case 67: case 68:
+ // M67, M68
+ dword_bit = MODAL_GROUP_M11;
+ gc_block.non_modal_command = int_value;
+ break;
+ #endif
default: FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); // [Unsupported M command]
}
// Check for more than one command per modal group violations in the current block
- // NOTE: Variable 'word_bit' is always assigned, if the command is valid.
- if ( bit_istrue(command_words,bit(word_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); }
- command_words |= bit(word_bit);
+ // NOTE: Variable 'dword_bit' is always assigned, if the command is valid.
+ if ( bit_istrue(command_dwords,dwbit(dword_bit)) ) { FAIL(STATUS_GCODE_MODAL_GROUP_VIOLATION); }
+ command_dwords |= dwbit(dword_bit);
break;
// NOTE: All remaining letters assign values.
@@ -288,40 +320,134 @@ uint8_t gc_execute_line(char *line)
legal g-code words and stores their value. Error-checking is performed later since some
words (I,J,K,L,P,R) have multiple connotations and/or depend on the issued commands. */
switch(letter){
- // case 'A': // Not supported
- // case 'B': // Not supported
- // case 'C': // Not supported
- // case 'D': // Not supported
- case 'F': word_bit = WORD_F; gc_block.values.f = value; break;
- // case 'H': // Not supported
- case 'I': word_bit = WORD_I; gc_block.values.ijk[X_AXIS] = value; ijk_words |= (1< MAX_TOOL_NUMBER) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); }
- gc_block.values.t = int_value;
- break;
- case 'X': word_bit = WORD_X; gc_block.values.xyz[X_AXIS] = value; axis_words |= (1<= NON_MODAL_DIGITAL_SYNC_ON) && (gc_block.non_modal_command <= NON_MODAL_DIGITAL_IMMEDIATE_OFF)) {
+ gc_block.values.p = int_value;
+ } else {
+ gc_block.values.p = value;
+ }
+ break;
+ #ifdef USE_OUTPUT_PWM
+ case 'Q': dword_bit = DWORD_Q; gc_block.values.q = value; break;
+ #endif
+ case 'R': dword_bit = DWORD_R; gc_block.values.r = value; break;
+ case 'S': dword_bit = DWORD_S; gc_block.values.s = value; break;
+ case 'T': dword_bit = DWORD_T;
+ if (value > MAX_TOOL_NUMBER) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); }
+ gc_block.values.t = int_value;
+ break;
+ // case 'X', 'Y', 'Z', 'A', 'B', 'C', 'U', 'V', 'W', 'D', 'E' or 'H' depending of AXIS_*_NAME.
+ // case imposible because same name can be used more than one for axis cloning
+ // case AXIS_1_NAME: case AXIS_2_NAME: case AXIS_3_NAME: case AXIS_4_NAME: case AXIS_5_NAME: case AXIS_6_NAME:
+ default:
+ if (letter == AXIS_1_NAME) {
+ dword_bit = DWORD_X; gc_block.values.xyz[AXIS_1] = value; axis_dwords |= (1< MAX_LINE_NUMBER) { FAIL(STATUS_GCODE_INVALID_LINE_NUMBER); } // [Exceeds max line number]
}
- // bit_false(value_words,bit(WORD_N)); // NOTE: Single-meaning value word. Set at end of error-checking.
+ // bit_false(value_dwords,dwbit(DWORD_N)); // NOTE: Single-meaning value word. Set at end of error-checking.
// Track for unused words at the end of error-checking.
// NOTE: Single-meaning value words are removed all at once at the end of error-checking, because
@@ -382,14 +508,14 @@ uint8_t gc_execute_line(char *line)
// is not defined after switching to G94 from G93.
// NOTE: For jogging, ignore prior feed rate mode. Enforce G94 and check for required F word.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
- if (bit_isfalse(value_words,bit(WORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); }
+ if (bit_isfalse(value_dwords,dwbit(DWORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); }
if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; }
} else {
if (gc_block.modal.feed_rate == FEED_RATE_MODE_INVERSE_TIME) { // = G93
// NOTE: G38 can also operate in inverse time, but is undefined as an error. Missing F word check added here.
if (axis_command == AXIS_COMMAND_MOTION_MODE) {
if ((gc_block.modal.motion != MOTION_MODE_NONE) && (gc_block.modal.motion != MOTION_MODE_SEEK)) {
- if (bit_isfalse(value_words,bit(WORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [F word missing]
+ if (bit_isfalse(value_dwords,dwbit(DWORD_F))) { FAIL(STATUS_GCODE_UNDEFINED_FEED_RATE); } // [F word missing]
}
}
// NOTE: It seems redundant to check for an F word to be passed after switching from G94 to G93. We would
@@ -407,7 +533,7 @@ uint8_t gc_execute_line(char *line)
} else { // = G94
// - In units per mm mode: If F word passed, ensure value is in mm/min, otherwise push last state value.
if (gc_state.modal.feed_rate == FEED_RATE_MODE_UNITS_PER_MIN) { // Last state is also G94
- if (bit_istrue(value_words,bit(WORD_F))) {
+ if (bit_istrue(value_dwords,dwbit(DWORD_F))) {
if (gc_block.modal.units == UNITS_MODE_INCHES) { gc_block.values.f *= MM_PER_INCH; }
} else {
gc_block.values.f = gc_state.feed_rate; // Push last state feed rate
@@ -415,58 +541,259 @@ uint8_t gc_execute_line(char *line)
} // Else, switching to G94 from G93, so don't push last state feed rate. Its undefined or the passed F word value.
}
}
- // bit_false(value_words,bit(WORD_F)); // NOTE: Single-meaning value word. Set at end of error-checking.
+ // bit_false(value_dwords,dwbit(DWORD_F)); // NOTE: Single-meaning value word. Set at end of error-checking.
// [4. Set spindle speed ]: S is negative (done.)
- if (bit_isfalse(value_words,bit(WORD_S))) { gc_block.values.s = gc_state.spindle_speed; }
- // bit_false(value_words,bit(WORD_S)); // NOTE: Single-meaning value word. Set at end of error-checking.
+ if (bit_isfalse(value_dwords,dwbit(DWORD_S))) { gc_block.values.s = gc_state.spindle_speed; }
+ // bit_false(value_dwords,dwbit(DWORD_S)); // NOTE: Single-meaning value word. Set at end of error-checking.
+
+ #ifdef USE_OUTPUT_PWM
+ if (dword_bit == MODAL_GROUP_M11) {
+ // [4.bis Set output PWM value]: Q value missing, Q is negative (done.)
+ if (bit_isfalse(value_dwords,dwbit(DWORD_Q))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [Q word missing]
+ // bit_false(value_dwords,dwbit(DWORD_Q)); // NOTE: Single-meaning value word. Set at end of error-checking.
+ }
+ #endif
// [5. Select tool ]: NOT SUPPORTED. Only tracks value. T is negative (done.) Not an integer. Greater than max tool value.
- // bit_false(value_words,bit(WORD_T)); // NOTE: Single-meaning value word. Set at end of error-checking.
+ // bit_false(value_dwords,dwbit(DWORD_T)); // NOTE: Single-meaning value word. Set at end of error-checking.
// [6. Change tool ]: N/A
// [7. Spindle control ]: N/A
// [8. Coolant control ]: N/A
// [9. Override control ]: Not supported except for a Grbl-only parking motion override control.
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
- if (bit_istrue(command_words,bit(MODAL_GROUP_M9))) { // Already set as enabled in parser.
- if (bit_istrue(value_words,bit(WORD_P))) {
+ if (bit_istrue(command_dwords,dwbit(MODAL_GROUP_M9))) { // Already set as enabled in parser.
+ if (bit_istrue(value_dwords,dwbit(DWORD_P))) {
if (gc_block.values.p == 0.0) { gc_block.modal.override = OVERRIDE_DISABLED; }
- bit_false(value_words,bit(WORD_P));
+ bit_false(value_dwords,dwbit(DWORD_P));
}
}
#endif
// [10. Dwell ]: P value missing. P is negative (done.) NOTE: See below.
if (gc_block.non_modal_command == NON_MODAL_DWELL) {
- if (bit_isfalse(value_words,bit(WORD_P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P word missing]
- bit_false(value_words,bit(WORD_P));
+ if (bit_isfalse(value_dwords,dwbit(DWORD_P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P word missing]
+ bit_false(value_dwords,dwbit(DWORD_P));
}
- // [11. Set active plane ]: N/A
+ // [11. Set active plane ]:
switch (gc_block.modal.plane_select) {
- case PLANE_SELECT_XY:
- axis_0 = X_AXIS;
- axis_1 = Y_AXIS;
- axis_linear = Z_AXIS;
+ case PLANE_SELECT_XY: /* axis_0 = X axis, axis_1 = Y axis, axis_linear = Z axis */
+ if (AXIS_1_NAME == 'X') { axis_0_mask |= (1< 3
+ for (idx=0; idx N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
if (gc_state.modal.coord_select != gc_block.modal.coord_select) {
if (!(settings_read_coord_data(gc_block.modal.coord_select,block_coord_system))) { FAIL(STATUS_SETTING_READ_FAIL); }
@@ -516,28 +843,28 @@ uint8_t gc_execute_line(char *line)
// [G10 Errors]: L missing and is not 2 or 20. P word missing. (Negative P value done.)
// [G10 L2 Errors]: R word NOT SUPPORTED. P value not 0 to nCoordSys(max 9). Axis words missing.
// [G10 L20 Errors]: P must be 0 to nCoordSys(max 9). Axis words missing.
- if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS) }; // [No axis words]
- if (bit_isfalse(value_words,((1< N_COORDINATE_SYSTEM) { FAIL(STATUS_GCODE_UNSUPPORTED_COORD_SYS); } // [Greater than N sys]
if (gc_block.values.l != 20) {
if (gc_block.values.l == 2) {
- if (bit_istrue(value_words,bit(WORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported]
+ if (bit_istrue(value_dwords,dwbit(DWORD_R))) { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [G10 L2 R not supported]
} else { FAIL(STATUS_GCODE_UNSUPPORTED_COMMAND); } // [Unsupported L]
}
- bit_false(value_words,(bit(WORD_L)|bit(WORD_P)));
+ bit_false(value_dwords,(dwbit(DWORD_L)|dwbit(DWORD_P)));
// Determine coordinate system to change and try to load from EEPROM.
if (coord_select > 0) { coord_select--; } // Adjust P1-P6 index to EEPROM coordinate data indexing.
else { coord_select = gc_block.modal.coord_select; } // Index P0 as the active coordinate system
-
+
// NOTE: Store parameter data in IJK values. By rule, they are not in use with this command.
if (!settings_read_coord_data(coord_select,gc_block.values.ijk)) { FAIL(STATUS_SETTING_READ_FAIL); } // [EEPROM read fail]
// Pre-calculate the coordinate data changes.
for (idx=0; idx WCS = MPos - G92 - TLO - WPos
@@ -552,12 +879,12 @@ uint8_t gc_execute_line(char *line)
break;
case NON_MODAL_SET_COORDINATE_OFFSET:
// [G92 Errors]: No axis words.
- if (!axis_words) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
+ if (!axis_dwords) { FAIL(STATUS_GCODE_NO_AXIS_WORDS); } // [No axis words]
// Update axes defined only in block. Offsets current system to defined value. Does not update when
// active coordinate system is selected, but is still active unless G92.1 disables it.
for (idx=0; idx G92 = MPos - WCS - TLO - WPos
gc_block.values.xyz[idx] = gc_state.position[idx]-block_coord_system[idx]-gc_block.values.xyz[idx];
if (idx == TOOL_LENGTH_OFFSET_AXIS) { gc_block.values.xyz[idx] -= gc_state.tool_length_offset; }
@@ -574,9 +901,9 @@ uint8_t gc_execute_line(char *line)
// modes applied. This includes the motion mode commands. We can now pre-compute the target position.
// NOTE: Tool offsets may be appended to these conversions when/if this feature is added.
if (axis_command != AXIS_COMMAND_TOOL_LENGTH_OFFSET ) { // TLO block any axis command.
- if (axis_words) {
+ if (axis_dwords) {
for (idx=0; idx 3
+ for (idx=0; idx= NON_MODAL_DIGITAL_SYNC_ON) && (gc_block.non_modal_command <= NON_MODAL_DIGITAL_IMMEDIATE_OFF)) {
+ if (bit_isfalse(value_dwords,dwbit(DWORD_P))) { FAIL(STATUS_GCODE_VALUE_WORD_MISSING); } // [P word missing]
+ if (gc_block.values.p > MAX_DIGITAL_OUTPUT) { FAIL(STATUS_GCODE_MAX_VALUE_EXCEEDED); }
+ bit_false(value_dwords,dwbit(DWORD_P));
+ }
+
// [0. Non-specific error-checks]: Complete unused value words check, i.e. IJK used when in arc
// radius mode, or axis words that aren't used in the block.
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
// Jogging only uses the F feed rate and XYZ value words. N is valid, but S and T are invalid.
- bit_false(value_words,(bit(WORD_N)|bit(WORD_F)));
+ bit_false(value_dwords,(dwbit(DWORD_N)|dwbit(DWORD_F)));
} else {
- bit_false(value_words,(bit(WORD_N)|bit(WORD_F)|bit(WORD_S)|bit(WORD_T))); // Remove single-meaning value words.
+ #ifdef USE_OUTPUT_PWM
+ bit_false(value_dwords,(dwbit(DWORD_N)|dwbit(DWORD_F)|dwbit(DWORD_Q)|dwbit(DWORD_S)|dwbit(DWORD_T))); // Remove single-meaning value words.
+ #else
+ bit_false(value_dwords,(dwbit(DWORD_N)|dwbit(DWORD_F)|dwbit(DWORD_S)|dwbit(DWORD_T))); // Remove single-meaning value words.
+ #endif
}
- if (axis_command) { bit_false(value_words,(bit(WORD_X)|bit(WORD_Y)|bit(WORD_Z))); } // Remove axis words.
- if (value_words) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words]
+#if N_AXIS > 3
+ if (axis_command) { bit_false(value_dwords,(dwbit(DWORD_X)|dwbit(DWORD_Y)|dwbit(DWORD_Z)|dwbit(DWORD_A)|dwbit(DWORD_B)|dwbit(DWORD_C)|dwbit(DWORD_U)|dwbit(DWORD_V)|dwbit(DWORD_W))); } // Remove axis words.
+#else
+ if (axis_command) { bit_false(value_dwords,(dwbit(DWORD_X)|dwbit(DWORD_Y)|dwbit(DWORD_Z))); } // Remove axis words.
+#endif
+ if (value_dwords) { FAIL(STATUS_GCODE_UNUSED_WORDS); } // [Unused words]
/* -------------------------------------------------------------------------------------
STEP 4: EXECUTE!!
@@ -845,45 +1273,49 @@ uint8_t gc_execute_line(char *line)
if (gc_parser_flags & GC_PARSER_JOG_MOTION) {
// Only distance and unit modal commands and G53 absolute override command are allowed.
// NOTE: Feed rate word and axis word checks have already been performed in STEP 3.
- if (command_words & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6 | bit(MODAL_GROUP_G0))) ) { FAIL(STATUS_INVALID_JOG_COMMAND) };
+ if (command_dwords & ~(bit(MODAL_GROUP_G3) | bit(MODAL_GROUP_G6) | bit(MODAL_GROUP_G0))) { FAIL(STATUS_INVALID_JOG_COMMAND) };
if (!(gc_block.non_modal_command == NON_MODAL_ABSOLUTE_OVERRIDE || gc_block.non_modal_command == NON_MODAL_NO_ACTION)) { FAIL(STATUS_INVALID_JOG_COMMAND); }
// Initialize planner data to current spindle and coolant modal state.
pl_data->spindle_speed = gc_state.spindle_speed;
plan_data.condition = (gc_state.modal.spindle | gc_state.modal.coolant);
+ #ifdef USE_OUTPUT_PWM
+ // Add output PWM value to planner data
+ pl_data->output_volts = gc_state.output_volts;
+ #endif
uint8_t status = jog_execute(&plan_data, &gc_block);
if (status == STATUS_OK) { memcpy(gc_state.position, gc_block.values.xyz, sizeof(gc_block.values.xyz)); }
return(status);
}
-
+
// If in laser mode, setup laser power based on current and past parser conditions.
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
- if ( !((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC)
+ if ( !((gc_block.modal.motion == MOTION_MODE_LINEAR) || (gc_block.modal.motion == MOTION_MODE_CW_ARC)
|| (gc_block.modal.motion == MOTION_MODE_CCW_ARC)) ) {
gc_parser_flags |= GC_PARSER_LASER_DISABLE;
}
- // Any motion mode with axis words is allowed to be passed from a spindle speed update.
+ // Any motion mode with axis words is allowed to be passed from a spindle speed update.
// NOTE: G1 and G0 without axis words sets axis_command to none. G28/30 are intentionally omitted.
// TODO: Check sync conditions for M3 enabled motions that don't enter the planner. (zero length).
- if (axis_words && (axis_command == AXIS_COMMAND_MOTION_MODE)) {
- gc_parser_flags |= GC_PARSER_LASER_ISMOTION;
+ if (axis_dwords && (axis_command == AXIS_COMMAND_MOTION_MODE)) {
+ gc_parser_flags |= GC_PARSER_LASER_ISMOTION;
} else {
// M3 constant power laser requires planner syncs to update the laser when changing between
// a G1/2/3 motion mode state and vice versa when there is no motion in the line.
if (gc_state.modal.spindle == SPINDLE_ENABLE_CW) {
- if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC)
+ if ((gc_state.modal.motion == MOTION_MODE_LINEAR) || (gc_state.modal.motion == MOTION_MODE_CW_ARC)
|| (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
- if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
+ if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC; // Change from G1/2/3 motion mode.
}
} else {
// When changing to a G1 motion mode without axis words from a non-G1/2/3 motion mode.
- if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
+ if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
gc_parser_flags |= GC_PARSER_LASER_FORCE_SYNC;
}
- }
+ }
}
}
}
@@ -905,20 +1337,22 @@ uint8_t gc_execute_line(char *line)
// [4. Set spindle speed ]:
if ((gc_state.spindle_speed != gc_block.values.s) || bit_istrue(gc_parser_flags,GC_PARSER_LASER_FORCE_SYNC)) {
- if (gc_state.modal.spindle != SPINDLE_DISABLE) {
+ if (gc_state.modal.spindle != SPINDLE_DISABLE) {
if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_ISMOTION)) {
if (bit_istrue(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
spindle_sync(gc_state.modal.spindle, 0.0);
- } else { spindle_sync(gc_state.modal.spindle, gc_block.values.s); }
+ } else {
+ spindle_sync(gc_state.modal.spindle, gc_block.values.s);
+ }
}
}
gc_state.spindle_speed = gc_block.values.s; // Update spindle speed state.
}
// NOTE: Pass zero spindle speed for all restricted laser motions.
if (bit_isfalse(gc_parser_flags,GC_PARSER_LASER_DISABLE)) {
- pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
+ pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use.
} // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already.
-
+
// [5. Select tool ]: NOT SUPPORTED. Only tracks tool value.
gc_state.tool = gc_block.values.t;
@@ -939,8 +1373,7 @@ uint8_t gc_execute_line(char *line)
// NOTE: Coolant M-codes are modal. Only one command per line is allowed. But, multiple states
// can exist at the same time, while coolant disable clears all states.
coolant_sync(gc_block.modal.coolant);
- if (gc_block.modal.coolant == COOLANT_DISABLE) { gc_state.modal.coolant = COOLANT_DISABLE; }
- else { gc_state.modal.coolant |= gc_block.modal.coolant; }
+ gc_state.modal.coolant = gc_block.modal.coolant;
}
pl_data->condition |= gc_state.modal.coolant; // Set condition flag for planner use.
@@ -1042,8 +1475,13 @@ uint8_t gc_execute_line(char *line)
pl_data->condition |= PL_COND_FLAG_RAPID_MOTION; // Set rapid motion condition flag.
mc_line(gc_block.values.xyz, pl_data);
} else if ((gc_state.modal.motion == MOTION_MODE_CW_ARC) || (gc_state.modal.motion == MOTION_MODE_CCW_ARC)) {
+ // GBGB TODO : Revoir mc_arc() pour le clonage et le renomage des axes...
mc_arc(gc_block.values.xyz, pl_data, gc_state.position, gc_block.values.ijk, gc_block.values.r,
- axis_0, axis_1, axis_linear, bit_istrue(gc_parser_flags,GC_PARSER_ARC_IS_CLOCKWISE));
+ axis_0, axis_1, axis_linear, axis_0_mask, axis_1_mask, axis_linear_mask,
+ axis_a, axis_b, axis_c, axis_a_mask, axis_b_mask, axis_c_mask,
+ axis_u, axis_v, axis_w, axis_u_mask, axis_v_mask, axis_w_mask,
+ axis_d, axis_e, axis_h, axis_d_mask, axis_e_mask, axis_h_mask,
+ bit_istrue(gc_parser_flags,GC_PARSER_ARC_IS_CLOCKWISE));
} else {
// NOTE: gc_block.values.xyz is returned from mc_probe_cycle with the updated position value. So
// upon a successful probing cycle, the machine position and the returned value should be the same.
@@ -1051,8 +1489,8 @@ uint8_t gc_execute_line(char *line)
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
#endif
gc_update_pos = mc_probe_cycle(gc_block.values.xyz, pl_data, gc_parser_flags);
- }
-
+ }
+
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
// in any intermediate location.
@@ -1061,7 +1499,7 @@ uint8_t gc_execute_line(char *line)
} else if (gc_update_pos == GC_UPDATE_POS_SYSTEM) {
gc_sync_position(); // gc_state.position[] = sys_position
} // == GC_UPDATE_POS_NONE
- }
+ }
}
// [21. Program flow ]:
@@ -1108,12 +1546,71 @@ uint8_t gc_execute_line(char *line)
system_flag_wco_change(); // Set to refresh immediately just in case something altered.
spindle_set_state(SPINDLE_DISABLE,0.0);
coolant_set_state(COOLANT_DISABLE);
+ digital_set_state(DIGITAL_OUTPUT_STATE_OFF);
}
report_feedback_message(MESSAGE_PROGRAM_END);
}
gc_state.modal.program_flow = PROGRAM_FLOW_RUNNING; // Reset program flow.
}
+ // [22. Digital output ]:
+ if ((gc_block.non_modal_command >= NON_MODAL_DIGITAL_SYNC_ON) && (gc_block.non_modal_command <= NON_MODAL_DIGITAL_IMMEDIATE_OFF)) {
+ uint8_t digital_mode = digital_get_state();
+ switch(gc_block.non_modal_command) {
+ case NON_MODAL_DIGITAL_SYNC_ON:
+ digital_sync(digital_mode | bit((uint8_t) gc_block.values.p));
+ break;
+ case NON_MODAL_DIGITAL_SYNC_OFF:
+ digital_sync(digital_mode & ~(bit((uint8_t) gc_block.values.p)));
+ break;
+ case NON_MODAL_DIGITAL_IMMEDIATE_ON:
+ digital_set_state(digital_mode | bit((uint8_t) gc_block.values.p));
+ break;
+ case NON_MODAL_DIGITAL_IMMEDIATE_OFF:
+ digital_set_state(digital_mode & ~(bit((uint8_t) gc_block.values.p)));
+ break;
+ }
+ }
+
+ #ifdef USE_OUTPUT_PWM
+ // [23. Output PWM ]:
+ if ((gc_state.output_volts != gc_block.values.q) || ((gc_block.non_modal_command >= NON_MODAL_ANALOG_OUTPUT_SYNC) && (gc_block.non_modal_command <= NON_MODAL_ANALOG_OUTPUT_IMMEDIATE))) {
+ switch(gc_block.non_modal_command) {
+ case NON_MODAL_ANALOG_OUTPUT_SYNC: // M67
+ if (gc_block.values.q != 0.0) {
+ output_pwm_sync(OUTPUT_PWM_STATE_ON, gc_block.values.q);
+ } else {
+ output_pwm_sync(OUTPUT_PWM_STATE_OFF, 0.0);
+ }
+ gc_state.output_last_command = gc_block.non_modal_command;
+ break;
+ case NON_MODAL_ANALOG_OUTPUT_IMMEDIATE: // M68
+ if (gc_block.values.q != 0.0) {
+ output_pwm_set_state(OUTPUT_PWM_STATE_ON, gc_block.values.q);
+ } else {
+ output_pwm_set_state(OUTPUT_PWM_STATE_OFF, 0.0);
+ }
+ gc_state.output_last_command = gc_block.non_modal_command;
+ break;
+ default:
+ // Changement de la valeur de sortie en dehors d'une commande M67/M68
+ // En fonction de la dernière commande stockée dans gc_state.output_last,
+ // on change immediatement ou synchronisé si respectivement NON_MODAL_ANALOG_OUTPUT_SYNC
+ // ou NON_MODAL_ANALOG_OUTPUT_IMMEDIATE.
+ // On laissera off si OUTPUT_PWM_STATE_OFF en cours (dernière action avec valeur 0.0).
+ if (gc_state.output_volts != 0.0) {
+ if (gc_state.output_last_command == NON_MODAL_ANALOG_OUTPUT_SYNC) {
+ output_pwm_sync(OUTPUT_PWM_STATE_ON, gc_block.values.q);
+ } else if (gc_state.output_last_command == NON_MODAL_ANALOG_OUTPUT_IMMEDIATE) {
+ output_pwm_set_state(OUTPUT_PWM_STATE_ON, gc_block.values.q);
+ }
+ }
+ break;
+ }
+ gc_state.output_volts = gc_block.values.q; // Update output volt state gc_state.output_volts .
+ }
+ #endif
+
// TODO: % to denote start of program.
return(STATUS_OK);
@@ -1125,7 +1622,7 @@ uint8_t gc_execute_line(char *line)
- Canned cycles
- Tool radius compensation
- - A,B,C-axes
+ - A,B,C-axes // A, B & C Supported in Ramps 1.4 grbl-Mega-5X version if N_AXIS > 3
- Evaluation of expressions
- Variables
- Override control (TBD)
diff --git a/grbl/gcode.h b/grbl/gcode.h
index 6cdc61b45..d35d80f05 100644
--- a/grbl/gcode.h
+++ b/grbl/gcode.h
@@ -2,6 +2,7 @@
gcode.h - rs274/ngc parser.
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -45,12 +46,16 @@
#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 MODAL_GROUP_M10 15 // [M62-M65] Digital output -Non-modal
+#ifdef USE_OUTPUT_PWM
+ #define MODAL_GROUP_M11 16 // [M67-M68] Analog output -Non-modal
+#endif
// 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
@@ -132,24 +137,44 @@
#define OVERRIDE_DISABLED 1 // Parking disabled.
#endif
+// Modal Group M10: Digital output (non modal)
+#define NON_MODAL_DIGITAL_SYNC_ON 62 // M62
+#define NON_MODAL_DIGITAL_SYNC_OFF 63 // M63
+#define NON_MODAL_DIGITAL_IMMEDIATE_ON 64 // M64
+#define NON_MODAL_DIGITAL_IMMEDIATE_OFF 65 // M65
+
+#ifdef USE_OUTPUT_PWM
+ // Modal Group M11: Analog output (PWM) (non modal)
+ #define NON_MODAL_ANALOG_OUTPUT_SYNC 67 // M162
+ #define NON_MODAL_ANALOG_OUTPUT_IMMEDIATE 68 // M164
+#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
-
+// Updated to 32 bits to support more than 16 values... Needed for new axis U, V & W
+#define DWORD_F 0
+#define DWORD_I 1
+#define DWORD_J 2
+#define DWORD_K 3
+#define DWORD_L 4
+#define DWORD_N 5
+#define DWORD_P 6
+#define DWORD_R 7
+#define DWORD_S 8
+#define DWORD_T 9
+#define DWORD_X 10
+#define DWORD_Y 11
+#define DWORD_Z 12
+#define DWORD_A 13
+#define DWORD_B 14
+#define DWORD_C 15
+#define DWORD_U 16
+#define DWORD_V 17
+#define DWORD_W 18
+#ifdef USE_OUTPUT_PWM
+ #define DWORD_Q 19
+#endif
// Define g-code parser position updating flags
#define GC_UPDATE_POS_TARGET 0 // Must be zero
#define GC_UPDATE_POS_SYSTEM 1
@@ -161,7 +186,7 @@
#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
#endif
@@ -198,27 +223,41 @@ typedef struct {
typedef struct {
float f; // Feed
+#if N_AXIS > 3
+ float ijk[N_AXIS]; // axes offsets for XYZ & AB(C)
+#else
float ijk[3]; // I,J,K Axis arc offsets
+#endif
uint8_t l; // G10 or canned cycles parameters
int32_t n; // Line number
+ #ifdef USE_OUTPUT_PWM
+ float q; // Output PWM valus
+ #endif
float p; // G10 or dwell parameters
- // float q; // G82 peck drilling
float r; // Arc radius
float s; // Spindle speed
uint8_t t; // Tool selection
+#if N_AXIS > 3
+ float xyz[N_AXIS]; // X,Y,Z Translational axes & A,B,(C)
+#else
float xyz[3]; // X,Y,Z Translational axes
+#endif
} gc_values_t;
typedef struct {
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
+ #ifdef USE_OUTPUT_PWM
+ float output_volts; // Output PWM value
+ uint8_t output_last_command; // Last command used to modify output PWM
+ #endif
+ 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.
diff --git a/grbl/grbl.h b/grbl/grbl.h
index fc8b8884a..3e6656f97 100644
--- a/grbl/grbl.h
+++ b/grbl/grbl.h
@@ -2,6 +2,7 @@
grbl.h - main Grbl include file
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2015-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -22,8 +23,8 @@
#define grbl_h
// Grbl versioning system
-#define GRBL_VERSION "1.1f"
-#define GRBL_VERSION_BUILD "20170802"
+#define GRBL_VERSION "1.2h"
+#define GRBL_VERSION_BUILD "20220109"
// Define standard libraries used by Grbl.
#include
@@ -47,6 +48,8 @@
#include "cpu_map.h"
#include "planner.h"
#include "coolant_control.h"
+#include "digital_control.h"
+#include "analog_control.h"
#include "eeprom.h"
#include "gcode.h"
#include "limits.h"
diff --git a/grbl/jog.c b/grbl/jog.c
index ee65b3dda..da4394a7f 100644
--- a/grbl/jog.c
+++ b/grbl/jog.c
@@ -2,6 +2,7 @@
jog.h - Jogging methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
diff --git a/grbl/jog.h b/grbl/jog.h
index c72624634..c483099d5 100644
--- a/grbl/jog.h
+++ b/grbl/jog.h
@@ -2,6 +2,7 @@
jog.h - Jogging methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
diff --git a/grbl/limits.c b/grbl/limits.c
index ebe540526..cff3a8ebf 100644
--- a/grbl/limits.c
+++ b/grbl/limits.c
@@ -2,9 +2,10 @@
limits.c - code pertaining to limit-switches and performing the homing cycle
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
-
+
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -18,9 +19,8 @@
You should have received a copy of the GNU General Public License
along with Grbl. If not, see .
*/
-
-#include "grbl.h"
+#include "grbl.h"
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
#ifndef HOMING_AXIS_SEARCH_SCALAR
@@ -32,163 +32,158 @@
void limits_init()
{
- #ifdef DEFAULTS_RAMPS_BOARD
- // Set as input pins
- MIN_LIMIT_DDR(0) &= ~(1< 3
+ MIN_LIMIT_DDR(3) &= ~(1< 4
+ MIN_LIMIT_DDR(4) &= ~(1< 5
+ MIN_LIMIT_DDR(5) &= ~(1< 3
+ MAX_LIMIT_DDR(3) &= ~(1< 4
+ MAX_LIMIT_DDR(4) &= ~(1< 5
+ MAX_LIMIT_DDR(5) &= ~(1< 3
+ MIN_LIMIT_PORT(3) &= ~(1< 4
+ MIN_LIMIT_PORT(4) &= ~(1< 5
+ MIN_LIMIT_PORT(5) &= ~(1< 3
+ MAX_LIMIT_PORT(3) &= ~(1< 4
+ MAX_LIMIT_PORT(4) &= ~(1< 5
+ MAX_LIMIT_PORT(5) &= ~(1< 3
+ MIN_LIMIT_PORT(3) |= (1< 4
+ MIN_LIMIT_PORT(4) |= (1< 5
+ MIN_LIMIT_PORT(5) |= (1< 3
+ MAX_LIMIT_PORT(3) |= (1< 4
+ MAX_LIMIT_PORT(4) |= (1< 5
+ MAX_LIMIT_PORT(5) |= (1<_LIMIT_PIN_MASK"
+ #endif
+ for (idx=0; idx= N_AXIS_LINEAR) && (max_travel == 0)) { max_travel = HOMING_AXIS_SEARCH_SCALAR * 360.0; }
+ if (max_travel < HOMING_AXIS_LOCATE_SCALAR) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_TRAVEL); }
}
}
+
// 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;
- #ifdef DEFAULTS_RAMPS_BOARD
- uint8_t limit_state, n_active_axis;
- uint8_t axislock[N_AXIS];
- do {
-
- system_convert_array_steps_to_mpos(target,sys_position);
-
- // Initialize and declare variables needed for homing routine.
- n_active_axis = 0;
- for (idx=0; idxfeed_rate = homing_rate; // Set current homing rate.
- plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
+ system_convert_array_steps_to_mpos(target,sys_position);
- 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 0);
- #else
- 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;
- n_active_axis = 0;
- for (idx=0; idxfeed_rate = homing_rate; // Set current homing rate.
- plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
+ // 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.
- 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 3
+ else if (idx==AXIS_4) { axislock[idx] &= ~(step_pin[AXIS_4]); }
+ #endif
+ #if N_AXIS > 4
+ else if (idx==AXIS_5) { axislock[idx] &= ~(step_pin[AXIS_5]); }
+ #endif
+ #if N_AXIS > 5
+ else if (idx==AXIS_6) { axislock[idx] &= ~(step_pin[AXIS_6]); }
#endif
- }
+ else { axislock[idx] &= ~(step_pin[A_MOTOR]|step_pin[B_MOTOR]); }
+ #else
+ axislock[idx] &= ~(step_pin[idx]);
+ #endif
}
}
- sys.homing_axis_lock = axislock;
+ sys.homing_axis_lock[idx] = axislock[idx];
}
+ }
- 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;
- }
+ 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;
}
+ }
- } while (STEP_MASK & axislock);
- st_reset(); // Immediately force kill steppers and reset step segment buffer.
- delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
+ } while (axislock_active(axislock));
+ 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;
+ // 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);
- #endif // DEFAULTS_RAMPS_BOARD
+ // 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
@@ -522,11 +400,11 @@ void limits_go_home(uint8_t cycle_mask)
#endif
#ifdef COREXY
- if (idx==X_AXIS) {
+ if (idx==AXIS_1) {
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) {
+ } else if (idx==AXIS_2) {
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;
diff --git a/grbl/limits.h b/grbl/limits.h
index 33fe09576..e1873b250 100644
--- a/grbl/limits.h
+++ b/grbl/limits.h
@@ -2,6 +2,7 @@
limits.h - code pertaining to limit-switches and performing the homing cycle
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -26,9 +27,6 @@
// Initialize the limits module
void limits_init();
-// Disables hard limits.
-void limits_disable();
-
// Returns limit state as a bit-wise uint8 variable.
uint8_t limits_get_state();
@@ -38,4 +36,8 @@ void limits_go_home(uint8_t cycle_mask);
// Check for soft limit violations
void limits_soft_check(float *target);
+// Hard limit error for RAMPS non interrupt hardware limits
+#ifdef ENABLE_RAMPS_HW_LIMITS
+ void ramps_hard_limit();
+#endif
#endif
diff --git a/grbl/main.c b/grbl/main.c
index 2b5438720..1b8125a75 100644
--- a/grbl/main.c
+++ b/grbl/main.c
@@ -2,6 +2,7 @@
main.c - An embedded CNC Controller with rs274/ngc (g-code) support
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -31,10 +32,25 @@ volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variab
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.
+uint8_t axis_X_mask = 0; // Global mask for axis X bits
+uint8_t axis_Y_mask = 0; // Global mask for axis Y bits
+uint8_t axis_Z_mask = 0; // Global mask for axis Z bits
+uint8_t axis_A_mask = 0; // Global mask for axis A bits
+uint8_t axis_B_mask = 0; // Global mask for axis B bits
+uint8_t axis_C_mask = 0; // Global mask for axis C bits
+uint8_t axis_U_mask = 0; // Global mask for axis U bits
+uint8_t axis_V_mask = 0; // Global mask for axis V bits
+uint8_t axis_W_mask = 0; // Global mask for axis W bits
+uint8_t axis_D_mask = 0; // Global mask for axis U bits
+uint8_t axis_E_mask = 0; // Global mask for axis V bits
+uint8_t axis_H_mask = 0; // Global mask for axis W bits
+unsigned char axis_name[N_AXIS]; // Global table of axis names
#ifdef DEBUG
volatile uint8_t sys_rt_exec_debug;
#endif
-
+#ifdef SORT_REPORT_BY_AXIS_NAME
+ uint8_t n_axis_report;
+#endif
int main(void)
{
@@ -44,6 +60,410 @@ int main(void)
stepper_init(); // Configure stepper pins and interrupt timers
system_init(); // Configure pinout pins and pin-change interrupt
+ // Initialize axis mask bits (ability to axis renaming and cloning)
+ // and global table of axis names.
+ if (AXIS_1_NAME == 'X') {
+ axis_X_mask |= (1< 3
+ if ((AXIS_4_NAME != AXIS_3_NAME) && (AXIS_4_NAME != AXIS_2_NAME) && (AXIS_4_NAME != AXIS_1_NAME)) {
+ n_axis_report++;
+ }
+ #endif
+ #if N_AXIS > 4
+ if ((AXIS_5_NAME != AXIS_4_NAME) && (AXIS_5_NAME != AXIS_3_NAME) && (AXIS_5_NAME != AXIS_2_NAME) && (AXIS_5_NAME != AXIS_1_NAME)) {
+ n_axis_report++;
+ }
+ #endif
+ #if N_AXIS > 5
+ if ((AXIS_6_NAME != AXIS_5_NAME) && (AXIS_6_NAME != AXIS_4_NAME) && (AXIS_6_NAME != AXIS_3_NAME) && (AXIS_6_NAME != AXIS_2_NAME) && (AXIS_6_NAME != AXIS_1_NAME)) {
+ n_axis_report++;
+ }
+ #endif
+ #else
+ n_axis_report = N_AXIS;
+ #endif
+ #endif
+
memset(sys_position,0,sizeof(sys_position)); // Clear machine position.
sei(); // Enable interrupts
@@ -54,7 +474,7 @@ int main(void)
#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
@@ -77,7 +497,7 @@ int main(void)
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.
+ 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;
@@ -88,7 +508,11 @@ int main(void)
serial_reset_read_buffer(); // Clear serial read buffer
gc_init(); // Set g-code parser to default state
spindle_init();
+ #ifdef USE_OUTPUT_PWM
+ output_pwm_init();
+ #endif
coolant_init();
+ digital_init();
limits_init();
probe_init();
sleep_init();
diff --git a/grbl/motion_control.c b/grbl/motion_control.c
index 6e11e35cb..db9257eb9 100644
--- a/grbl/motion_control.c
+++ b/grbl/motion_control.c
@@ -2,6 +2,7 @@
motion_control.c - high level interface for issuing motion commands
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -85,7 +86,11 @@ void mc_line(float *target, plan_line_data_t *pl_data)
// 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)
+ uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t axis_0_mask, uint8_t axis_1_mask, uint8_t axis_linear_mask,
+ uint8_t axis_a, uint8_t axis_b, uint8_t axis_c, uint8_t axis_a_mask, uint8_t axis_b_mask, uint8_t axis_c_mask,
+ uint8_t axis_u, uint8_t axis_v, uint8_t axis_w, uint8_t axis_u_mask, uint8_t axis_v_mask, uint8_t axis_w_mask,
+ uint8_t axis_d, uint8_t axis_e, uint8_t axis_h, uint8_t axis_d_mask, uint8_t axis_e_mask, uint8_t axis_h_mask,
+ uint8_t is_clockwise_arc)
{
float center_axis0 = position[axis_0] + offset[axis_0];
float center_axis1 = position[axis_1] + offset[axis_1];
@@ -93,6 +98,9 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
float r_axis1 = -offset[axis_1];
float rt_axis0 = target[axis_0] - center_axis0;
float rt_axis1 = target[axis_1] - center_axis1;
+ float a_per_segment, b_per_segment, c_per_segment;
+ float u_per_segment, v_per_segment, w_per_segment;
+ float d_per_segment, e_per_segment, h_per_segment;
// 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);
@@ -113,13 +121,22 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
// 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;
+ 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.
}
-
+
float theta_per_segment = angular_travel/segments;
float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments;
+ if ( axis_a_mask ) a_per_segment = (target[axis_a] - position[axis_a])/segments; else a_per_segment = 0;
+ if ( axis_b_mask ) b_per_segment = (target[axis_b] - position[axis_b])/segments; else b_per_segment = 0;
+ if ( axis_c_mask ) c_per_segment = (target[axis_c] - position[axis_c])/segments; else c_per_segment = 0;
+ if ( axis_u_mask ) u_per_segment = (target[axis_u] - position[axis_u])/segments; else u_per_segment = 0;
+ if ( axis_v_mask ) v_per_segment = (target[axis_v] - position[axis_v])/segments; else v_per_segment = 0;
+ if ( axis_w_mask ) w_per_segment = (target[axis_w] - position[axis_w])/segments; else w_per_segment = 0;
+ if ( axis_d_mask ) d_per_segment = (target[axis_d] - position[axis_d])/segments; else d_per_segment = 0;
+ if ( axis_e_mask ) e_per_segment = (target[axis_e] - position[axis_e])/segments; else e_per_segment = 0;
+ if ( axis_h_mask ) h_per_segment = (target[axis_h] - position[axis_h])/segments; else h_per_segment = 0;
/* 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.
@@ -176,9 +193,184 @@ void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *of
}
// Update arc_target location
+ /*
position[axis_0] = center_axis0 + r_axis0;
position[axis_1] = center_axis1 + r_axis1;
position[axis_linear] += linear_per_segment;
+ * */
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ if (bit_istrue((1< 4
+ if (bit_istrue((1< 5
+ if (bit_istrue((1< 3
+ #ifdef HOMING_CYCLE_3
+ limits_go_home(HOMING_CYCLE_3); // Homing cycle 3
+ #endif
+ #ifdef HOMING_CYCLE_4
+ limits_go_home(HOMING_CYCLE_4); // Homing cycle 4
+ #endif
+ #ifdef HOMING_CYCLE_5
+ limits_go_home(HOMING_CYCLE_5); // Homing cycle 5
+ #endif
+ #endif
}
protocol_execute_realtime(); // Check for reset and set system abort.
@@ -304,6 +505,8 @@ uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_
protocol_execute_realtime(); // Check and execute run-time commands
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
+ sys.step_control = STEP_CONTROL_NORMAL_OP; // Restore step control to normal operation
+ // fix grbl-Mega-5X's issue #214
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.
@@ -378,8 +581,8 @@ void mc_reset()
// 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) {
+ (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.
diff --git a/grbl/motion_control.h b/grbl/motion_control.h
index 442ab2e9f..7be04690f 100644
--- a/grbl/motion_control.h
+++ b/grbl/motion_control.h
@@ -2,9 +2,10 @@
motion_control.h - high level interface for issuing motion commands
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
-
+
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
@@ -28,10 +29,6 @@
#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)
-
// 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
@@ -43,7 +40,11 @@ void mc_line(float *target, plan_line_data_t *pl_data);
// 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);
+ uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t axis_0_mask, uint8_t axis_1_mask, uint8_t axis_linear_mask,
+ uint8_t axis_a, uint8_t axis_b, uint8_t axis_c, uint8_t axis_a_mask, uint8_t axis_b_mask, uint8_t axis_c_mask,
+ uint8_t axis_u, uint8_t axis_v, uint8_t axis_w, uint8_t axis_u_mask, uint8_t axis_v_mask, uint8_t axis_w_mask,
+ uint8_t axis_d, uint8_t axis_e, uint8_t axis_h, uint8_t axis_d_mask, uint8_t axis_e_mask, uint8_t axis_h_mask,
+ uint8_t is_clockwise_arc);
// Dwell for a specific number of seconds
void mc_dwell(float seconds);
diff --git a/grbl/nuts_bolts.c b/grbl/nuts_bolts.c
index 9d89a8d06..1b3e45848 100644
--- a/grbl/nuts_bolts.c
+++ b/grbl/nuts_bolts.c
@@ -2,6 +2,7 @@
nuts_bolts.c - Shared functions
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -111,18 +112,18 @@ uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
// 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
- }
+ 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
+ }
}
@@ -163,11 +164,21 @@ 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;
+ uint8_t idx, j;
+ bool isclone;
float magnitude = 0.0;
for (idx=0; idxcondition & PL_COND_FLAG_SYSTEM_MOTION) {
+ 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];
+ position_steps[AXIS_1] = system_convert_corexy_to_x_axis_steps(sys_position);
+ position_steps[AXIS_2] = system_convert_corexy_to_y_axis_steps(sys_position);
+ position_steps[AXIS_3] = sys_position[AXIS_3];
+ #if N_AXIS > 3
+ position_steps[AXIS_4] = sys_position[AXIS_4];
+ #endif
+ #if N_AXIS > 4
+ position_steps[AXIS_5] = sys_position[AXIS_5];
+ #endif
+ #if N_AXIS > 5
+ position_steps[AXIS_6] = sys_position[AXIS_6];
+ #endif
#else
- memcpy(position_steps, sys_position, sizeof(sys_position));
+ 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]));
+ block->steps[A_MOTOR] = labs((target_steps[AXIS_1]-position_steps[AXIS_1]) + (target_steps[AXIS_2]-position_steps[AXIS_2]));
+ block->steps[B_MOTOR] = labs((target_steps[AXIS_1]-position_steps[AXIS_1]) - (target_steps[AXIS_2]-position_steps[AXIS_2]));
#endif
for (idx=0; idxstep_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];
+ delta_mm = (target_steps[AXIS_1]-position_steps[AXIS_1] + target_steps[AXIS_2]-position_steps[AXIS_2])/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];
+ delta_mm = (target_steps[AXIS_1]-position_steps[AXIS_1] - target_steps[AXIS_2]+position_steps[AXIS_2])/settings.steps_per_mm[idx];
} else {
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
}
@@ -366,15 +376,11 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
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
+ #endif
unit_vec[idx] = delta_mm; // Store unit vector numerator
// Set direction bits. Bit enabled always means direction is negative.
- #ifdef DEFAULTS_RAMPS_BOARD
- if (delta_mm < 0.0 ) { block->direction_bits[idx] |= get_direction_pin_mask(idx); }
- #else
- if (delta_mm < 0.0 ) { block->direction_bits |= get_direction_pin_mask(idx); }
- #endif // DEFAULTS_RAMPS_BOARD
+ if (delta_mm < 0.0 ) { block->direction_bits[idx] |= get_direction_pin_mask(idx); }
}
// Bail if this is a zero-length block. Highly unlikely to occur.
@@ -390,7 +396,7 @@ uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
// Store programmed rate.
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { block->programmed_rate = block->rapid_rate; }
- else {
+ else {
block->programmed_rate = pl_data->feed_rate;
if (block->condition & PL_COND_FLAG_INVERSE_TIME) { block->programmed_rate *= block->millimeters; }
}
@@ -480,10 +486,10 @@ void plan_sync_position()
uint8_t idx;
for (idx=0; idx 0) {
+ buf[i++] = n % 10;
+ n /= 10;
+ }
+
+ for (; i > 0; i--)
+ serial_write('0' + buf[i-1]);
+}
+
+
void print_uint32_base10(uint32_t n)
{
if (n == 0) {
diff --git a/grbl/print.h b/grbl/print.h
index 31e0a576c..91a9c2c51 100644
--- a/grbl/print.h
+++ b/grbl/print.h
@@ -2,6 +2,7 @@
print.h - Functions for formatting output strings
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -29,6 +30,7 @@ void printPgmString(const char *s);
void printInteger(long n);
+void print_uint16_base10(uint16_t n);
void print_uint32_base10(uint32_t n);
// Prints an uint8 variable in base 10.
diff --git a/grbl/probe.c b/grbl/probe.c
index 60c9073ad..b2b437630 100644
--- a/grbl/probe.c
+++ b/grbl/probe.c
@@ -2,6 +2,7 @@
probe.c - code pertaining to probing methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
diff --git a/grbl/probe.h b/grbl/probe.h
index 03d5fd329..11b07bb3d 100644
--- a/grbl/probe.h
+++ b/grbl/probe.h
@@ -2,6 +2,7 @@
probe.h - code pertaining to probing methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
diff --git a/grbl/protocol.c b/grbl/protocol.c
index b21485147..acffc1c12 100644
--- a/grbl/protocol.c
+++ b/grbl/protocol.c
@@ -2,6 +2,7 @@
protocol.c - controls Grbl execution protocol and procedures
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -53,8 +54,8 @@ void protocol_main_loop()
report_feedback_message(MESSAGE_ALARM_LOCK);
sys.state = STATE_ALARM; // Ensure alarm state is set.
} else {
- // Check if the safety door is open.
sys.state = STATE_IDLE;
+ // Check if the safety door is open.
if (system_check_safety_door_ajar()) {
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state.
@@ -71,6 +72,8 @@ void protocol_main_loop()
uint8_t line_flags = 0;
uint8_t char_counter = 0;
uint8_t c;
+ uint8_t crlf_flag = 0;
+
for (;;) {
// Process one line of incoming serial data, as the data becomes available. Performs an
@@ -78,6 +81,14 @@ void protocol_main_loop()
while((c = serial_read()) != SERIAL_NO_DATA) {
if ((c == '\n') || (c == '\r')) { // End of line reached
+ if (c == '\r') {
+ // Track CR to detect Windows CRLF
+ crlf_flag = 1;
+ } else if (c != '\n') {
+ // This is not a CRLF sequence
+ crlf_flag = 0;
+ }
+
protocol_execute_realtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to calling function upon system abort
@@ -91,8 +102,12 @@ void protocol_main_loop()
// Report line overflow error.
report_status_message(STATUS_OVERFLOW);
} else if (line[0] == 0) {
- // Empty or comment line. For syncing purposes.
- report_status_message(STATUS_OK);
+ // Dont send 2 OK when character is LF just after a CR
+ // Send the OK reply when CR is received or if LF is received without CR just before.
+ if ((c == '\r') || ((c == '\n') && (crlf_flag != 1))) {
+ // Empty or comment line. For syncing purposes.
+ report_status_message(STATUS_OK);
+ }
} else if (line[0] == '$') {
// Grbl '$' system command
report_status_message(system_execute_line(line));
@@ -158,10 +173,10 @@ void protocol_main_loop()
protocol_execute_realtime(); // Runtime command check point.
if (sys.abort) { return; } // Bail to main() program loop to reset system.
-
+
#ifdef SLEEP_ENABLE
// Check for sleep conditions and execute auto-park, if timeout duration elapses.
- sleep_check();
+ sleep_check();
#endif
}
@@ -237,6 +252,10 @@ void protocol_exec_rt_system()
// the user and a GUI time to do what is needed before resetting, like killing the
// incoming stream. The same could be said about soft limits. While the position is not
// lost, continued streaming could cause a serious crash if by chance it gets executed.
+ if (sys_rt_exec_state & EXEC_STATUS_REPORT) {
+ report_realtime_status();
+ system_clear_exec_state_flag(EXEC_STATUS_REPORT);
+ }
} while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
}
system_clear_exec_alarm(); // Clear alarm
@@ -263,14 +282,14 @@ void protocol_exec_rt_system()
// State check for allowable states for hold methods.
if (!(sys.state & (STATE_ALARM | STATE_CHECK_MODE))) {
-
+
// If in CYCLE or JOG states, immediately initiate a motion HOLD.
if (sys.state & (STATE_CYCLE | STATE_JOG)) {
if (!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) { // Block, if already holding.
st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
sys.step_control = STEP_CONTROL_EXECUTE_HOLD; // Initiate suspend state with active flag.
if (sys.state == STATE_JOG) { // Jog cancelled upon any hold event, except for sleeping.
- if (!(rt_exec & EXEC_SLEEP)) { sys.suspend |= SUSPEND_JOG_CANCEL; }
+ if (!(rt_exec & EXEC_SLEEP)) { sys.suspend |= SUSPEND_JOG_CANCEL; }
}
}
}
@@ -321,12 +340,12 @@ void protocol_exec_rt_system()
// are executed if the door switch closes and the state returns to HOLD.
sys.suspend |= SUSPEND_SAFETY_DOOR_AJAR;
}
-
+
}
if (rt_exec & EXEC_SLEEP) {
if (sys.state == STATE_ALARM) { sys.suspend |= (SUSPEND_RETRACT_COMPLETE|SUSPEND_HOLD_COMPLETE); }
- sys.state = STATE_SLEEP;
+ sys.state = STATE_SLEEP;
}
system_clear_exec_state_flag((EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP));
@@ -450,8 +469,10 @@ void protocol_exec_rt_system()
last_s_override = max(last_s_override,MIN_SPINDLE_SPEED_OVERRIDE);
if (last_s_override != sys.spindle_speed_ovr) {
- bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
sys.spindle_speed_ovr = last_s_override;
+ // NOTE: Spindle speed overrides during HOLD state are taken care of by suspend function.
+ if (sys.state == STATE_IDLE) { spindle_set_state(gc_state.modal.spindle, gc_state.spindle_speed); }
+ else { bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); }
sys.report_ovr_counter = 0; // Set to report change immediately
}
@@ -466,8 +487,9 @@ void protocol_exec_rt_system()
// NOTE: Since coolant state always performs a planner sync whenever it changes, the current
// run state can be determined by checking the parser state.
+ // NOTE: Coolant overrides only operate during IDLE, CYCLE, HOLD, and JOG states. Ignored otherwise.
if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
- if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) {
+ if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_JOG))) {
uint8_t coolant_state = gc_state.modal.coolant;
if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
if (coolant_state & COOLANT_MIST_ENABLE) { bit_false(coolant_state,COOLANT_MIST_ENABLE); }
@@ -483,13 +505,6 @@ void protocol_exec_rt_system()
}
}
- #ifdef DEBUG
- if (sys_rt_exec_debug) {
- report_realtime_debug();
- sys_rt_exec_debug = 0;
- }
- #endif
-
// Reload step segment buffer
if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG)) {
st_prep_buffer();
@@ -524,26 +539,28 @@ static void protocol_exec_rt_suspend()
restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant);
restore_spindle_speed = gc_state.spindle_speed;
} else {
- restore_condition = block->condition;
+ restore_condition = (block->condition & PL_COND_SPINDLE_MASK) | coolant_get_state();
restore_spindle_speed = block->spindle_speed;
}
#ifdef DISABLE_LASER_DURING_HOLD
- if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
+ if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
}
#endif
while (sys.suspend) {
- if (sys.abort) { return; }
+ if (sys.abort) {
+ return;
+ }
// Block until initial hold is complete and the machine has stopped motion.
if (sys.suspend & SUSPEND_HOLD_COMPLETE) {
- // Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
+ // Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
// the safety door and sleep states.
if (sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP)) {
-
+
// Handles retraction motions and de-energizing.
if (bit_isfalse(sys.suspend,SUSPEND_RETRACT_COMPLETE)) {
@@ -556,7 +573,7 @@ static void protocol_exec_rt_suspend()
coolant_set_state(COOLANT_DISABLE); // De-energize
#else
-
+
// Get current position and store restore location and spindle retract waypoint.
system_convert_array_steps_to_mpos(parking_target,sys_position);
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
@@ -617,7 +634,7 @@ static void protocol_exec_rt_suspend()
} else {
-
+
if (sys.state == STATE_SLEEP) {
report_feedback_message(MESSAGE_SLEEP_MODE);
// Spindle and coolant should already be stopped, but do it again just to be sure.
@@ -626,8 +643,8 @@ static void protocol_exec_rt_suspend()
st_go_idle(); // Disable steppers
while (!(sys.abort)) { protocol_exec_rt_system(); } // Do nothing until reset.
return; // Abort received. Return to re-initialize.
- }
-
+ }
+
// Allows resuming from parking/safety door. Actively checks if safety door is closed and ready to resume.
if (sys.state == STATE_SAFETY_DOOR) {
if (!(system_check_safety_door_ajar())) {
@@ -673,7 +690,7 @@ static void protocol_exec_rt_suspend()
// Block if safety door re-opened during prior restore actions.
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin.
- coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_FLOOD)));
+ coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_MIST)));
delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND);
}
}
@@ -692,8 +709,8 @@ static void protocol_exec_rt_suspend()
// restore parking motion should logically be valid, either by returning to the
// original position through valid machine space or by not moving at all.
pl_data->feed_rate = PARKING_PULLOUT_RATE;
- pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state
- pl_data->spindle_speed = restore_spindle_speed;
+ pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state
+ pl_data->spindle_speed = restore_spindle_speed;
mc_parking_motion(restore_target, pl_data);
}
}
@@ -748,7 +765,7 @@ static void protocol_exec_rt_suspend()
}
}
-
+
#ifdef SLEEP_ENABLE
// Check for sleep conditions and execute auto-park, if timeout duration elapses.
// Sleep is valid for both hold and door states, if the spindle or coolant are on or
diff --git a/grbl/protocol.h b/grbl/protocol.h
index 56acba30f..6a434aed6 100644
--- a/grbl/protocol.h
+++ b/grbl/protocol.h
@@ -2,6 +2,7 @@
protocol.h - controls Grbl execution protocol and procedures
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
diff --git a/grbl/report.c b/grbl/report.c
index 07598494a..3c3e518ac 100644
--- a/grbl/report.c
+++ b/grbl/report.c
@@ -2,6 +2,7 @@
report.c - reporting and messaging methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -27,7 +28,9 @@
*/
#include "grbl.h"
+#include
+static uint8_t report_grbl_settings_running;
// Internal report utilities to reduce flash with repetitive tasks turned into functions.
void report_util_setting_prefix(uint8_t n) { serial_write('$'); print_uint8_base10(n); serial_write('='); }
@@ -36,12 +39,84 @@ static void report_util_feedback_line_feed() { serial_write(']'); report_util_li
static void report_util_gcode_modes_G() { printPgmString(PSTR(" G")); }
static void report_util_gcode_modes_M() { printPgmString(PSTR(" M")); }
// static void report_util_comment_line_feed() { serial_write(')'); report_util_line_feed(); }
+
static void report_util_axis_values(float *axis_value) {
- uint8_t idx;
- for (idx=0; idx3
+ if (AXIS_4_NAME == axis_name_order[i]) {
+ printFloat_CoordValue(axis_value[3]);
+ n_report++;
+ if (n_report < (n_axis_report)) { serial_write(','); }
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ #if N_AXIS >4
+ if (AXIS_5_NAME == axis_name_order[i]) {
+ printFloat_CoordValue(axis_value[4]);
+ n_report++;
+ if (n_report < (n_axis_report)) { serial_write(','); }
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ #if N_AXIS >5
+ if (AXIS_6_NAME == axis_name_order[i]) {
+ printFloat_CoordValue(axis_value[5]);
+ n_report++;
+ if (n_report < (n_axis_report)) { serial_write(','); }
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ }
+ #else // #ifdef SORT_REPORT_BY_AXIS_NAME
+ for (uint8_t idx=0; idx 3
+ if (AXIS_4_NAME == axis_name_order[i]) {
+ serial_write(AXIS_4_NAME);
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ #if N_AXIS > 4
+ if (AXIS_5_NAME == axis_name_order[i]) {
+ serial_write(AXIS_5_NAME);
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ #if N_AXIS > 5
+ if (AXIS_6_NAME == axis_name_order[i]) {
+ serial_write(AXIS_6_NAME);
+ #ifdef REPORT_VALUE_FOR_AXIS_NAME_ONCE
+ axis_name_order[i] = '\0';
+ #endif
+ }
+ #endif
+ }
+ #else
+ // Output axis_names in order of axis number
+ serial_write(AXIS_1_NAME);
+ serial_write(AXIS_2_NAME);
+ serial_write(AXIS_3_NAME);
+ #if N_AXIS > 3
+ serial_write(AXIS_4_NAME);
+ #endif
+ #if N_AXIS > 4
+ serial_write(AXIS_5_NAME);
+ #endif
+ #if N_AXIS > 5
+ serial_write(AXIS_6_NAME);
+ #endif
+ #endif
+ report_util_feedback_line_feed();
printPgmString(PSTR("[OPT:")); // Generate compile-time build option list
- serial_write('V');
- serial_write('N');
- serial_write('M');
+ //--------------------------------------------------------------------
+ // ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789*$# => Option letter
+ // ! !!! !!! !!! !!! ! !! !! !!! => ! = Used
+ //--------------------------------------------------------------------
+
+ serial_write('V'); // Variable spindle, standard.
+ serial_write('N'); // Line number reporting, standard.
+ serial_write('M'); // M7 mist coolant, standard.
+ serial_write('G'); // Safety door support, standard.
#ifdef COREXY
serial_write('C');
#endif
@@ -380,21 +547,27 @@ void report_build_info(char *line)
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
serial_write('T');
#endif
- #ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
- serial_write('A');
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ serial_write('S');
#endif
- #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
+ #ifdef USE_DIGITAL_INPUT
serial_write('D');
#endif
+ #ifdef USE_OUTPUT_PWM
+ serial_write('Q');
+ #endif
+ #ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
+ serial_write('A');
+ #endif
#ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
serial_write('0');
#endif
- #ifdef ENABLE_SOFTWARE_DEBOUNCE
- serial_write('S');
- #endif
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
serial_write('R');
#endif
+ #ifndef HOMING_INIT_LOCK
+ serial_write('L');
+ #endif
#ifndef ENABLE_RESTORE_EEPROM_WIPE_ALL // NOTE: Shown when disabled.
serial_write('*');
#endif
@@ -413,15 +586,13 @@ void report_build_info(char *line)
#ifndef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // NOTE: Shown when disabled.
serial_write('W');
#endif
- #ifndef HOMING_INIT_LOCK
- serial_write('L');
- #endif
-
// NOTE: Compiled values, like override increments/max/min values, may be added at some point later.
serial_write(',');
print_uint8_base10(BLOCK_BUFFER_SIZE-1);
serial_write(',');
print_uint8_base10(RX_BUFFER_SIZE);
+ serial_write(',');
+ print_uint8_base10(settings.flags);
report_util_feedback_line_feed();
}
@@ -543,14 +714,21 @@ void report_realtime_status()
printPgmString(PSTR("|Pn:"));
if (prb_pin_state) { serial_write('P'); }
if (lim_pin_state) {
- if (bit_istrue(lim_pin_state,bit(X_AXIS))) { serial_write('X'); }
- if (bit_istrue(lim_pin_state,bit(Y_AXIS))) { serial_write('Y'); }
- if (bit_istrue(lim_pin_state,bit(Z_AXIS))) { serial_write('Z'); }
+ if (bit_istrue(lim_pin_state,bit(AXIS_1))) { serial_write(AXIS_1_NAME); }
+ if (bit_istrue(lim_pin_state,bit(AXIS_2))) { serial_write(AXIS_2_NAME); }
+ if (bit_istrue(lim_pin_state,bit(AXIS_3))) { serial_write(AXIS_3_NAME); }
+ #if N_AXIS > 3
+ if (bit_istrue(lim_pin_state,bit(AXIS_4))) { serial_write(AXIS_4_NAME); }
+ #endif
+ #if N_AXIS > 4
+ if (bit_istrue(lim_pin_state,bit(AXIS_5))) { serial_write(AXIS_5_NAME); }
+ #endif
+ #if N_AXIS > 5
+ if (bit_istrue(lim_pin_state,bit(AXIS_6))) { serial_write(AXIS_6_NAME); }
+ #endif
}
if (ctrl_pin_state) {
- #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
- if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_SAFETY_DOOR)) { serial_write('D'); }
- #endif
+ if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_SAFETY_DOOR)) { serial_write('D'); }
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_RESET)) { serial_write('R'); }
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_FEED_HOLD)) { serial_write('H'); }
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_CYCLE_START)) { serial_write('S'); }
@@ -558,6 +736,11 @@ void report_realtime_status()
}
#endif
+ #ifdef DEBUG
+ printPgmString(PSTR("|Dbg:"));
+ // Other debugs here...
+ #endif
+
#ifdef REPORT_FIELD_WORK_COORD_OFFSET
if (sys.report_wco_counter > 0) { sys.report_wco_counter--; }
else {
@@ -571,11 +754,14 @@ void report_realtime_status()
#endif
#ifdef REPORT_FIELD_OVERRIDES
- if (sys.report_ovr_counter > 0) { sys.report_ovr_counter--; }
- else {
+ if (sys.report_ovr_counter > 0) {
+ sys.report_ovr_counter--;
+ } else {
if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
sys.report_ovr_counter = (REPORT_OVR_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
- } else { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1); }
+ } else {
+ sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1);
+ }
printPgmString(PSTR("|Ov:"));
print_uint8_base10(sys.f_override);
serial_write(',');
@@ -585,7 +771,8 @@ void report_realtime_status()
uint8_t sp_state = spindle_get_state();
uint8_t cl_state = coolant_get_state();
- if (sp_state || cl_state) {
+ uint8_t dg_state = digital_get_state();
+ if (sp_state || cl_state || dg_state) {
printPgmString(PSTR("|A:"));
if (sp_state) { // != SPINDLE_STATE_DISABLE
if (sp_state == SPINDLE_STATE_CW) { serial_write('S'); } // CW
@@ -593,7 +780,34 @@ void report_realtime_status()
}
if (cl_state & COOLANT_STATE_FLOOD) { serial_write('F'); }
if (cl_state & COOLANT_STATE_MIST) { serial_write('M'); }
- }
+ if (dg_state) { // One or more digital output is active
+ serial_write('D');
+ printDgState(dg_state);
+ }
+ #ifdef USE_OUTPUT_PWM
+ #endif
+ }
+ }
+ #endif
+
+ #ifdef USE_OUTPUT_PWM
+ uint8_t ot_state = output_pwm_get_state();
+ if (ot_state) { // Analog output (PWM) in active
+ if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
+ // If reporting in machine position, print the PWM value of output
+ printPgmString(PSTR("|Qm:"));
+ print_uint16_base10(output_compute_pwm_value(sys.output_volts));
+ } else {
+ // If reporting in working position, print the output_volts value
+ printPgmString(PSTR("|Qw:"));
+ printFloat(sys.output_volts, N_DECIMAL_SETTINGVALUE);
+ }
+ /* pour debug calculs PWM
+ * serial_write(',');
+ * print_uint16_base10(output_compute_pwm_value(sys.output_volts));
+ * serial_write(',');
+ * printFloat(o_pwm_gradient(), N_DECIMAL_SETTINGVALUE);
+ */
}
#endif
@@ -602,9 +816,100 @@ void report_realtime_status()
}
+// Print digital input / output status
+void report_digital_status(uint8_t dg_state)
+{
+ printPgmString(PSTR("[D:"));
+ printDgState(dg_state);
+ serial_write(']');
+ report_util_line_feed();
+}
+
+void printDgState(uint8_t dg_state)
+{
+ #ifdef USE_DIGITAL_INPUT
+ if (dg_state & DIGITAL_INPUT_STATE_P3) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_INPUT_STATE_P2) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_INPUT_STATE_P1) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_INPUT_STATE_P0) { serial_write('1'); } else {serial_write('0');}
+ #endif
+ if (dg_state & DIGITAL_OUTPUT_STATE_P3) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_OUTPUT_STATE_P2) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_OUTPUT_STATE_P1) { serial_write('1'); } else {serial_write('0');}
+ if (dg_state & DIGITAL_OUTPUT_STATE_P0) { serial_write('1'); } else {serial_write('0');}
+}
+
+
#ifdef DEBUG
- void report_realtime_debug()
- {
+// Report debug string on serial
+void report_debug_string(char *line)
+{
+ printPgmString(PSTR("{debug("));
+ printString(line);
+ printPgmString(PSTR(")}"));
+ report_util_line_feed();
+}
+
+// Report debug int_8 and int_16 value
+// Those functions accept the variable's name string as optional argument
+void report_debug_int_8(uint8_t val, ...)
+{
+ va_list args;
+ char *valname;
+
+ va_start(args, val);
+ valname = va_arg(args, char *);
+ va_end(args);
+
+ printPgmString(PSTR("{debug("));
+ if ( valname != NULL ) {
+ printString(valname);
+ printString(" = ");
}
-#endif
+ print_uint8_base10(val);
+ printPgmString(PSTR(")}"));
+ report_util_line_feed();
+}
+
+void report_debug_int_16(uint16_t val, ...)
+{
+ va_list args;
+ char *valname;
+
+ va_start(args, val);
+ valname = va_arg(args, char *);
+ va_end(args);
+
+ printPgmString(PSTR("{debug("));
+ if ( valname != NULL ) {
+ printString(valname);
+ printString(" = ");
+ }
+ print_uint16_base10(val);
+ printPgmString(PSTR(")}"));
+ report_util_line_feed();
+}
+
+// Report debug float value
+// This function accept the variable's name string as optional argument
+void report_debug_float(float val, ...)
+{
+ va_list args;
+ char *valname;
+
+ va_start(args, val);
+ valname = va_arg(args, char *);
+ va_end(args);
+
+ printPgmString(PSTR("{debug("));
+ if ( valname != NULL ) {
+ printString(valname);
+ printString(" = ");
+ }
+ printFloat(val, N_DECIMAL_SETTINGVALUE);
+ printPgmString(PSTR(")}"));
+ report_util_line_feed();
+}
+
+#endif // DEBUG
diff --git a/grbl/report.h b/grbl/report.h
index f1480026a..33cd9184b 100644
--- a/grbl/report.h
+++ b/grbl/report.h
@@ -2,6 +2,7 @@
report.h - reporting and messaging methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -101,6 +102,7 @@ void report_grbl_help();
// Prints Grbl global settings
void report_grbl_settings();
+uint8_t is_report_grbl_settings_running();
// Prints an echo of the pre-parsed line received right before execution.
void report_echo_line_received(char *line);
@@ -124,8 +126,14 @@ void report_execute_startup_message(char *line, uint8_t status_code);
// Prints build info and user info
void report_build_info(char *line);
+// Print digital input / output status
+void report_digital_status(uint8_t dg_state);
+void printDgState(uint8_t dg_state);
+
#ifdef DEBUG
- void report_realtime_debug();
+ void report_debug_string(char *line);
+ void report_debug_int_8(uint8_t val, ...);
+ void report_debug_int_16(uint16_t val, ...);
#endif
#endif
diff --git a/grbl/serial.c b/grbl/serial.c
index 381812972..3f33d14a3 100644
--- a/grbl/serial.c
+++ b/grbl/serial.c
@@ -2,6 +2,7 @@
serial.c - Low level functions for sending and recieving bytes via the serial port
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -24,8 +25,8 @@
#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;
+volatile uint8_t serial_rx_buffer[RX_RING_BUFFER];
+volatile uint8_t serial_rx_buffer_head = 0;
volatile uint8_t serial_rx_buffer_tail = 0;
uint8_t serial_tx_buffer[TX_RING_BUFFER];
@@ -148,7 +149,7 @@ ISR(SERIAL_RX)
// 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_RESET: mc_reset(); break; // Call motion control reset routine (soft reset).
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
@@ -156,11 +157,12 @@ ISR(SERIAL_RX)
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:
+ 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);
+ system_set_exec_state_flag(EXEC_MOTION_CANCEL);
+ serial_reset_read_buffer(); // Vide un reste éventuel de données dans le buffer
}
- break;
+ 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
@@ -190,6 +192,9 @@ ISR(SERIAL_RX)
if (next_head != serial_rx_buffer_tail) {
serial_rx_buffer[serial_rx_buffer_head] = data;
serial_rx_buffer_head = next_head;
+ } else {
+ // Indicate serial buffer overflow critical event.
+ system_set_exec_alarm(EXEC_ALARM_SERIAL_RX_OVERFLOW);
}
}
}
@@ -200,3 +205,14 @@ void serial_reset_read_buffer()
{
serial_rx_buffer_tail = serial_rx_buffer_head;
}
+
+
+void serial_putstring(char* StringPtr)
+{
+ int i;
+ int len = strlen(StringPtr);
+ for(i=0; i 3
+ .steps_per_mm[AXIS_4] = DEFAULT_AXIS4_STEPS_PER_UNIT,
+ .max_rate[AXIS_4] = DEFAULT_AXIS4_MAX_RATE,
+ .acceleration[AXIS_4] = DEFAULT_AXIS4_ACCELERATION,
+ .max_travel[AXIS_4] = (-DEFAULT_AXIS4_MAX_TRAVEL),
+#endif
+#if N_AXIS > 4
+ .steps_per_mm[AXIS_5] = DEFAULT_AXIS5_STEPS_PER_UNIT,
+ .max_rate[AXIS_5] = DEFAULT_AXIS5_MAX_RATE,
+ .acceleration[AXIS_5] = DEFAULT_AXIS5_ACCELERATION,
+ .max_travel[AXIS_5] = (-DEFAULT_AXIS5_MAX_TRAVEL),
+#endif
+#if N_AXIS > 5
+ .steps_per_mm[AXIS_6] = DEFAULT_AXIS6_STEPS_PER_UNIT,
+ .max_rate[AXIS_6] = DEFAULT_AXIS6_MAX_RATE,
+ .acceleration[AXIS_6] = DEFAULT_AXIS6_ACCELERATION,
+ .max_travel[AXIS_6] = (-DEFAULT_AXIS6_MAX_TRAVEL),
+#endif
+};
// 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.
+ 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);
@@ -67,46 +130,7 @@ void write_global_settings()
// 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.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
- settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
- settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK;
- settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK;
- settings.status_report_mask = DEFAULT_STATUS_REPORT_MASK;
- settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
- settings.arc_tolerance = DEFAULT_ARC_TOLERANCE;
-
- settings.rpm_max = DEFAULT_SPINDLE_RPM_MAX;
- settings.rpm_min = DEFAULT_SPINDLE_RPM_MIN;
-
- settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
- settings.homing_feed_rate = DEFAULT_HOMING_FEED_RATE;
- settings.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE;
- settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
- settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
-
- settings.flags = 0;
- if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
- if (DEFAULT_LASER_MODE) { settings.flags |= BITFLAG_LASER_MODE; }
- if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
- if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
- if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
- if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; }
- if (DEFAULT_INVERT_LIMIT_PINS) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
- if (DEFAULT_INVERT_PROBE_PIN) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
-
- settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
- settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
- settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
- settings.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
- settings.max_rate[Y_AXIS] = DEFAULT_Y_MAX_RATE;
- settings.max_rate[Z_AXIS] = DEFAULT_Z_MAX_RATE;
- settings.acceleration[X_AXIS] = DEFAULT_X_ACCELERATION;
- settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION;
- settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION;
- settings.max_travel[X_AXIS] = (-DEFAULT_X_MAX_TRAVEL);
- settings.max_travel[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL);
- settings.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL);
-
+ settings = defaults;
write_global_settings();
}
@@ -292,7 +316,18 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) {
case 32:
if (int_value) { settings.flags |= BITFLAG_LASER_MODE; }
else { settings.flags &= ~BITFLAG_LASER_MODE; }
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ spindle_init(); // Re-initialize spindle / laser calibration
+ #endif
break;
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ case 33: settings.laser_max = value; spindle_init(); break; // Re-initialize laser calibration
+ case 34: settings.laser_min = value; spindle_init(); break; // Re-initialize laser calibration
+ #endif
+ #ifdef USE_OUTPUT_PWM
+ case 35: settings.volts_max = value; output_pwm_init(); break;
+ case 36: settings.volts_min = value; output_pwm_init(); break;
+ #endif
default:
return(STATUS_INVALID_STATEMENT);
}
@@ -308,62 +343,84 @@ void settings_init() {
report_status_message(STATUS_SETTING_READ_FAIL);
settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
report_grbl_settings();
+ do {} while (is_report_grbl_settings_running()); // Wait for report settings complete
}
+ #ifdef DEBUG
+ else
+ {
+ report_debug_string("settings_init() Ok.");
+ }
+ #endif
}
// Returns step pin mask according to Grbl internal axis indexing.
uint8_t get_step_pin_mask(uint8_t axis_idx)
{
- #ifdef DEFAULTS_RAMPS_BOARD
- if ( axis_idx == X_AXIS ) { return((1< 3
+ if ( axis_idx == AXIS_4 ) { return((1< 4
+ if ( axis_idx == AXIS_5 ) { return((1< 5
+ if ( axis_idx == AXIS_6 ) { return((1< 3
+ if ( axis_idx == AXIS_4 ) { return((1< 4
+ if ( axis_idx == AXIS_5 ) { return((1< 5
+ if ( axis_idx == AXIS_6 ) { return((1< 3
+ if ( axis_idx == AXIS_4 ) { return((1< 4
+ if ( axis_idx == AXIS_5 ) { return((1< 5
+ if ( axis_idx == AXIS_6 ) { return((1< 3
+ if ( axis_idx == AXIS_4 ) { return((1< 4
+ if ( axis_idx == AXIS_5 ) { return((1< 5
+ if ( axis_idx == AXIS_6 ) { return((1< steps_per_degre for rotationals axis (AXIS_4 and AXIS_5)
float max_rate[N_AXIS];
float acceleration[N_AXIS];
float max_travel[N_AXIS];
@@ -90,10 +100,18 @@ typedef struct {
uint8_t status_report_mask; // Mask to indicate desired report data.
float junction_deviation;
float arc_tolerance;
-
+
float rpm_max;
float rpm_min;
-
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ float laser_max;
+ float laser_min;
+ #endif
+ #ifdef USE_OUTPUT_PWM
+ float volts_max;
+ float volts_min;
+ #endif
+
uint8_t flags; // Contains default boolean settings
uint8_t homing_dir_mask;
diff --git a/grbl/spindle_control.c b/grbl/spindle_control.c
index 8982dfa2e..3d9de3f74 100644
--- a/grbl/spindle_control.c
+++ b/grbl/spindle_control.c
@@ -2,6 +2,7 @@
spindle_control.c - spindle control methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2017 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -22,11 +23,27 @@
#include "grbl.h"
-static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
+static float spindle_pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
void spindle_init()
-{
+{
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ if (settings.flags & BITFLAG_LASER_MODE) {
+ // In laser mode, spindle routines use laser pin output
+ // Force PWM output zero to avoid PWM output flash on laser output
+ LASER_TCCRA_REGISTER &= ~(1<= 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) {
- if (rpm == 0.0) { // S0 disables spindle
- 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;
- }
- } 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);
+ uint16_t pwm_value;
+ rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ if (settings.flags & BITFLAG_LASER_MODE) {
+ // Calculate PWM register value based on laser max/min settings and programmed rpm.
+ if ((settings.laser_min >= settings.laser_max) || (rpm >= settings.laser_max)) {
+ // No PWM range possible. Set simple on/off pin state.
+ sys.spindle_speed = settings.laser_max;
+ pwm_value = LASER_PWM_MAX_VALUE;
+ } else if (rpm <= settings.laser_min) {
+ if (rpm == 0.0) { // S0 disables laser
+ sys.spindle_speed = 0.0;
+ pwm_value = LASER_PWM_OFF_VALUE;
+ } else { // Set minimum PWM output
+ sys.spindle_speed = settings.laser_min;
+ pwm_value = LASER_PWM_MIN_VALUE;
+ }
+ } else {
+ // Compute intermediate PWM value with linear laser power 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.laser_min) * spindle_pwm_gradient) + LASER_PWM_MIN_VALUE;
+ }
+ } else {
+ #endif
+ // 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) {
+ if (rpm == 0.0) { // S0 disables spindle
+ 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;
+ }
+ } 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) * spindle_pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
+ }
+ #ifdef SEPARATE_SPINDLE_LASER_PIN
+ }
+ #endif
+ #ifndef INVERT_SPINDLE_PWM_VALUES
+ return(pwm_value);
+ #else
+ return(SPINDLE_PWM_MAX_VALUE - pwm_value);
+ #endif
}
#endif
diff --git a/grbl/spindle_control.h b/grbl/spindle_control.h
index 7e4145e8a..9bb4f4ee6 100644
--- a/grbl/spindle_control.h
+++ b/grbl/spindle_control.h
@@ -2,6 +2,7 @@
spindle_control.h - spindle control methods
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
diff --git a/grbl/stepper.c b/grbl/stepper.c
index d0fc3aa71..0abf35c7a 100644
--- a/grbl/stepper.c
+++ b/grbl/stepper.c
@@ -2,6 +2,7 @@
stepper.c - stepper motor driver: executes motion plans using stepper motors
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
@@ -57,21 +58,12 @@
// NOTE: This data is copied from the prepped planner blocks so that the planner blocks may be
// discarded when entirely consumed and completed by the segment buffer. Also, AMASS alters this
// data for its own use.
-#ifdef DEFAULTS_RAMPS_BOARD
- typedef struct {
+typedef struct {
uint32_t steps[N_AXIS];
uint32_t step_event_count;
uint8_t direction_bits[N_AXIS];
uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
- } st_block_t;
-#else
- typedef struct {
- uint32_t steps[N_AXIS];
- uint32_t step_event_count;
- uint8_t direction_bits;
- uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
- } st_block_t;
-#endif // Ramps Board
+} st_block_t;
static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
@@ -97,24 +89,29 @@ typedef struct {
// Used by the bresenham line algorithm
uint32_t counter_x, // Counter variables for the bresenham line tracer
counter_y,
+ #if N_AXIS == 4
+ counter_z,
+ counter_4;
+ #elif N_AXIS == 5
+ counter_z,
+ counter_4,
+ counter_5;
+ #elif N_AXIS == 6
+ counter_z,
+ counter_4,
+ counter_5,
+ counter_6;
+ #else
counter_z;
+ #endif
#ifdef STEP_PULSE_DELAY
- #ifdef DEFAULTS_RAMPS_BOARD
- uint8_t step_bits[N_AXIS]; // Stores out_bits output to complete the step pulse delay
- #else
- uint8_t step_bits; // Stores out_bits output to complete the step pulse delay
- #endif // Ramps Board
+ uint8_t step_bits[N_AXIS]; // Stores out_bits output to complete the step pulse delay
#endif
- uint8_t execute_step; // Flags step execution for each interrupt.
- uint8_t step_pulse_time; // Step pulse reset time after step rise
- #ifdef DEFAULTS_RAMPS_BOARD
- uint8_t step_outbits[N_AXIS]; // The next stepping-bits to be output
- uint8_t dir_outbits[N_AXIS];
- #else
- uint8_t step_outbits; // The next stepping-bits to be output
- uint8_t dir_outbits;
- #endif //Ramps Board
+ uint8_t execute_step; // Flags step execution for each interrupt.
+ uint8_t step_pulse_time; // Step pulse reset time after step rise
+ uint8_t step_outbits[N_AXIS]; // The next stepping-bits to be output
+ uint8_t dir_outbits[N_AXIS];
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
uint32_t steps[N_AXIS];
#endif
@@ -132,13 +129,8 @@ static uint8_t segment_buffer_head;
static uint8_t segment_next_head;
// Step and direction port invert masks.
-#ifdef DEFAULTS_RAMPS_BOARD
- static uint8_t step_port_invert_mask[N_AXIS];
- static uint8_t dir_port_invert_mask[N_AXIS];
-#else
- static uint8_t step_port_invert_mask;
- static uint8_t dir_port_invert_mask;
-#endif // Ramps Board
+static uint8_t step_port_invert_mask[N_AXIS];
+static uint8_t dir_port_invert_mask[N_AXIS];
// Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though.
static volatile uint8_t busy;
@@ -176,7 +168,7 @@ typedef struct {
float decelerate_after; // Deceleration ramp start measured from end of block (mm)
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
- uint16_t current_spindle_pwm;
+ uint16_t current_spindle_pwm;
} st_prep_t;
static st_prep_t prep;
@@ -223,37 +215,44 @@ static st_prep_t prep;
// Stepper state initialization. Cycle should only start if the st.cycle_start flag is
// enabled. Startup init and limits call this function but shouldn't start the cycle.
-#ifdef DEFAULTS_RAMPS_BOARD
- int idx;
-#endif // Ramps Board
+int idx; // GBGB ???
void st_wake_up()
{
- #ifdef DEFAULTS_RAMPS_BOARD
- int idx;
- #endif // Ramps Board
-
+ int idx;
+
// Enable stepper drivers.
- #ifdef DEFAULTS_RAMPS_BOARD
- if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
- STEPPER_DISABLE_PORT(0) |= (1 << STEPPER_DISABLE_BIT(0));
- STEPPER_DISABLE_PORT(1) |= (1 << STEPPER_DISABLE_BIT(1));
- STEPPER_DISABLE_PORT(2) |= (1 << STEPPER_DISABLE_BIT(2));
- } else {
- STEPPER_DISABLE_PORT(0) &= ~(1 << STEPPER_DISABLE_BIT(0));
- STEPPER_DISABLE_PORT(1) &= ~(1 << STEPPER_DISABLE_BIT(1));
- STEPPER_DISABLE_PORT(2) &= ~(1 << STEPPER_DISABLE_BIT(2));
- }
- // Initialize stepper output bits to ensure first ISR call does not step.
- for (idx = 0; idx < N_AXIS; idx++) {
- st.step_outbits[idx] = step_port_invert_mask[idx];
- }
- #else
- if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1< 3
+ STEPPER_DISABLE_PORT(3) |= (1 << STEPPER_DISABLE_BIT(3));
+ #endif
+ #if N_AXIS > 4
+ STEPPER_DISABLE_PORT(4) |= (1 << STEPPER_DISABLE_BIT(4));
+ #endif
+ #if N_AXIS > 5
+ STEPPER_DISABLE_PORT(5) |= (1 << STEPPER_DISABLE_BIT(5));
+ #endif
+ } else {
+ STEPPER_DISABLE_PORT(0) &= ~(1 << STEPPER_DISABLE_BIT(0));
+ STEPPER_DISABLE_PORT(1) &= ~(1 << STEPPER_DISABLE_BIT(1));
+ STEPPER_DISABLE_PORT(2) &= ~(1 << STEPPER_DISABLE_BIT(2));
+ #if N_AXIS > 3
+ STEPPER_DISABLE_PORT(3) &= ~(1 << STEPPER_DISABLE_BIT(3));
+ #endif
+ #if N_AXIS > 4
+ STEPPER_DISABLE_PORT(4) &= ~(1 << STEPPER_DISABLE_BIT(4));
+ #endif
+ #if N_AXIS > 5
+ STEPPER_DISABLE_PORT(5) &= ~(1 << STEPPER_DISABLE_BIT(5));
+ #endif
+ }
+ // Initialize stepper output bits to ensure first ISR call does not step.
+ for (idx = 0; idx < N_AXIS; idx++) {
+ st.step_outbits[idx] = step_port_invert_mask[idx];
+ }
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
#ifdef STEP_PULSE_DELAY
@@ -288,20 +287,33 @@ void st_go_idle()
pin_state = true; // Override. Disable steppers.
}
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = !pin_state; } // Apply pin invert.
- #ifdef DEFAULTS_RAMPS_BOARD
- if (pin_state) {
- STEPPER_DISABLE_PORT(0) |= (1 << STEPPER_DISABLE_BIT(0));
- STEPPER_DISABLE_PORT(1) |= (1 << STEPPER_DISABLE_BIT(1));
- STEPPER_DISABLE_PORT(2) |= (1 << STEPPER_DISABLE_BIT(2));
- } else {
- STEPPER_DISABLE_PORT(0) &= ~(1 << STEPPER_DISABLE_BIT(0));
- STEPPER_DISABLE_PORT(1) &= ~(1 << STEPPER_DISABLE_BIT(1));
- STEPPER_DISABLE_PORT(2) &= ~(1 << STEPPER_DISABLE_BIT(2));
- }
- #else
- if (pin_state) { STEPPERS_DISABLE_PORT |= (1< 3
+ STEPPER_DISABLE_PORT(3) |= (1 << STEPPER_DISABLE_BIT(3));
+ #endif
+ #if N_AXIS > 4
+ STEPPER_DISABLE_PORT(4) |= (1 << STEPPER_DISABLE_BIT(4));
+ #endif
+ #if N_AXIS > 5
+ STEPPER_DISABLE_PORT(5) |= (1 << STEPPER_DISABLE_BIT(5));
+ #endif
+ } else {
+ STEPPER_DISABLE_PORT(0) &= ~(1 << STEPPER_DISABLE_BIT(0));
+ STEPPER_DISABLE_PORT(1) &= ~(1 << STEPPER_DISABLE_BIT(1));
+ STEPPER_DISABLE_PORT(2) &= ~(1 << STEPPER_DISABLE_BIT(2));
+ #if N_AXIS > 3
+ STEPPER_DISABLE_PORT(3) &= ~(1 << STEPPER_DISABLE_BIT(3));
+ #endif
+ #if N_AXIS > 4
+ STEPPER_DISABLE_PORT(4) &= ~(1 << STEPPER_DISABLE_BIT(4));
+ #endif
+ #if N_AXIS > 5
+ STEPPER_DISABLE_PORT(5) &= ~(1 << STEPPER_DISABLE_BIT(5));
+ #endif
+ }
}
@@ -355,39 +367,60 @@ void st_go_idle()
// with probing and homing cycles that require true real-time positions.
ISR(TIMER1_COMPA_vect)
{
- #ifdef DEFAULTS_RAMPS_BOARD
- int i;
- #endif // Ramps Board
+ int i;
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
+ // Adding limit check status to implement hardware limits for RAMPS
+ // outside the changepin interrupt wich cannot be used
+ #ifdef ENABLE_RAMPS_HW_LIMITS
+ if (limits_get_state()) {
+ ramps_hard_limit();
+ }
+ #endif
+
// Set the direction pins a couple of nanoseconds before we step the steppers
- #ifdef DEFAULTS_RAMPS_BOARD
- DIRECTION_PORT(0) = (DIRECTION_PORT(0) & ~(1 << DIRECTION_BIT(0))) | st.dir_outbits[0];
- DIRECTION_PORT(1) = (DIRECTION_PORT(1) & ~(1 << DIRECTION_BIT(1))) | st.dir_outbits[1];
- DIRECTION_PORT(2) = (DIRECTION_PORT(2) & ~(1 << DIRECTION_BIT(2))) | st.dir_outbits[2];
- #else
- DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK);
- #endif // Ramps Boafd
+ DIRECTION_PORT(0) = (DIRECTION_PORT(0) & ~(1 << DIRECTION_BIT(0))) | st.dir_outbits[0];
+ DIRECTION_PORT(1) = (DIRECTION_PORT(1) & ~(1 << DIRECTION_BIT(1))) | st.dir_outbits[1];
+ DIRECTION_PORT(2) = (DIRECTION_PORT(2) & ~(1 << DIRECTION_BIT(2))) | st.dir_outbits[2];
+ #if N_AXIS > 3
+ DIRECTION_PORT(3) = (DIRECTION_PORT(3) & ~(1 << DIRECTION_BIT(3))) | st.dir_outbits[3];
+ #endif
+ #if N_AXIS > 4
+ DIRECTION_PORT(4) = (DIRECTION_PORT(4) & ~(1 << DIRECTION_BIT(4))) | st.dir_outbits[4];
+ #endif
+ #if N_AXIS > 5
+ DIRECTION_PORT(5) = (DIRECTION_PORT(5) & ~(1 << DIRECTION_BIT(5))) | st.dir_outbits[5];
+ #endif
// Then pulse the stepping pins
- #ifdef DEFAULTS_RAMPS_BOARD
- #ifdef STEP_PULSE_DELAY
- st.step_bits[0] = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | st.step_outbits[0]; // Store out_bits to prevent overwriting.
- st.step_bits[1] = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | st.step_outbits[1]; // Store out_bits to prevent overwriting.
- st.step_bits[2] = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | st.step_outbits[2]; // Store out_bits to prevent overwriting.
- #else
- STEP_PORT(0) = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | st.step_outbits[0];
- STEP_PORT(1) = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | st.step_outbits[1];
- STEP_PORT(2) = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | st.step_outbits[2];
+ #ifdef STEP_PULSE_DELAY
+ st.step_bits[0] = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | st.step_outbits[0]; // Store out_bits to prevent overwriting.
+ st.step_bits[1] = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | st.step_outbits[1]; // Store out_bits to prevent overwriting.
+ st.step_bits[2] = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | st.step_outbits[2]; // Store out_bits to prevent overwriting.
+ #if N_AXIS > 3
+ st.step_bits[3] = (STEP_PORT(3) & ~(1 << STEP_BIT(3))) | st.step_outbits[3]; // Store out_bits to prevent overwriting.
#endif
- #else
- #ifdef STEP_PULSE_DELAY
- st.step_bits = (STEP_PORT & ~STEP_MASK) | st.step_outbits; // Store out_bits to prevent overwriting.
- #else // Normal operation
- STEP_PORT = (STEP_PORT & ~STEP_MASK) | st.step_outbits;
+ #if N_AXIS > 4
+ st.step_bits[4] = (STEP_PORT(4) & ~(1 << STEP_BIT(4))) | st.step_outbits[4]; // Store out_bits to prevent overwriting.
#endif
- #endif // Ramps Board
+ #if N_AXIS > 5
+ st.step_bits[5] = (STEP_PORT(5) & ~(1 << STEP_BIT(5))) | st.step_outbits[5]; // Store out_bits to prevent overwriting.
+ #endif
+ #else
+ STEP_PORT(0) = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | st.step_outbits[0];
+ STEP_PORT(1) = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | st.step_outbits[1];
+ STEP_PORT(2) = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | st.step_outbits[2];
+ #if N_AXIS > 3
+ STEP_PORT(3) = (STEP_PORT(3) & ~(1 << STEP_BIT(3))) | st.step_outbits[3];
+ #endif
+ #if N_AXIS > 4
+ STEP_PORT(4) = (STEP_PORT(4) & ~(1 << STEP_BIT(4))) | st.step_outbits[4];
+ #endif
+ #if N_AXIS > 5
+ STEP_PORT(5) = (STEP_PORT(5) & ~(1 << STEP_BIT(5))) | st.step_outbits[5];
+ #endif
+ #endif
// Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after
// exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler.
@@ -420,20 +453,33 @@ ISR(TIMER1_COMPA_vect)
st.exec_block = &st_block_buffer[st.exec_block_index];
// Initialize Bresenham line and distance counters
- st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
+ #if N_AXIS == 4
+ st.counter_x = st.counter_y = st.counter_z = st.counter_4 = (st.exec_block->step_event_count >> 1);
+ #elif N_AXIS == 5
+ st.counter_x = st.counter_y = st.counter_z = st.counter_4 = st.counter_5 = (st.exec_block->step_event_count >> 1);
+ #elif N_AXIS == 6
+ st.counter_x = st.counter_y = st.counter_z = st.counter_4 = st.counter_5 = st.counter_6 = (st.exec_block->step_event_count >> 1);
+ #else
+ st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
+ #endif
}
- #ifdef DEFAULTS_RAMPS_BOARD
- for (i = 0; i < N_AXIS; i++)
- st.dir_outbits[i] = st.exec_block->direction_bits[i] ^ dir_port_invert_mask[i];
- #else
- st.dir_outbits = st.exec_block->direction_bits ^ dir_port_invert_mask;
- #endif // Ramps Board
+ for (i = 0; i < N_AXIS; i++)
+ st.dir_outbits[i] = st.exec_block->direction_bits[i] ^ dir_port_invert_mask[i];
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
// With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level.
- st.steps[X_AXIS] = st.exec_block->steps[X_AXIS] >> st.exec_segment->amass_level;
- st.steps[Y_AXIS] = st.exec_block->steps[Y_AXIS] >> st.exec_segment->amass_level;
- st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level;
+ st.steps[AXIS_1] = st.exec_block->steps[AXIS_1] >> st.exec_segment->amass_level;
+ st.steps[AXIS_2] = st.exec_block->steps[AXIS_2] >> st.exec_segment->amass_level;
+ st.steps[AXIS_3] = st.exec_block->steps[AXIS_3] >> st.exec_segment->amass_level;
+ #if N_AXIS > 3
+ st.steps[AXIS_4] = st.exec_block->steps[AXIS_4] >> st.exec_segment->amass_level;
+ #endif
+ #if N_AXIS > 4
+ st.steps[AXIS_5] = st.exec_block->steps[AXIS_5] >> st.exec_segment->amass_level;
+ #endif
+ #if N_AXIS > 5
+ st.steps[AXIS_6] = st.exec_block->steps[AXIS_6] >> st.exec_segment->amass_level;
+ #endif
#endif
// Set real-time spindle output as segment is loaded, just prior to the first step.
@@ -454,95 +500,95 @@ ISR(TIMER1_COMPA_vect)
if (sys_probe_state == PROBE_ACTIVE) { probe_state_monitor(); }
// Reset step out bits.
- #ifdef DEFAULTS_RAMPS_BOARD
- for (i = 0; i < N_AXIS; i++)
- st.step_outbits[i] = 0;
- #else
- st.step_outbits = 0;
- #endif // Ramps Board
+ for (i = 0; i < N_AXIS; i++)
+ st.step_outbits[i] = 0;
// Execute step displacement profile by Bresenham line algorithm
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
- st.counter_x += st.steps[X_AXIS];
+ st.counter_x += st.steps[AXIS_1];
#else
- st.counter_x += st.exec_block->steps[X_AXIS];
+ st.counter_x += st.exec_block->steps[AXIS_1];
#endif
- #ifdef DEFAULTS_RAMPS_BOARD
- if (st.counter_x > st.exec_block->step_event_count) {
- st.step_outbits[X_AXIS] |= (1<step_event_count;
- if (st.exec_block->direction_bits[X_AXIS] & (1< st.exec_block->step_event_count) {
- st.step_outbits |= (1<step_event_count;
- if (st.exec_block->direction_bits & (1< st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_1] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_1] & (1<steps[Y_AXIS];
+ st.counter_y += st.exec_block->steps[AXIS_2];
#endif
- #ifdef DEFAULTS_RAMPS_BOARD
- if (st.counter_y > st.exec_block->step_event_count) {
- st.step_outbits[Y_AXIS] |= (1<step_event_count;
- if (st.exec_block->direction_bits[Y_AXIS] & (1< st.exec_block->step_event_count) {
- st.step_outbits |= (1<step_event_count;
- if (st.exec_block->direction_bits & (1< st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_2] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_2] & (1<steps[Z_AXIS];
+ st.counter_z += st.exec_block->steps[AXIS_3];
#endif
- #ifdef DEFAULTS_RAMPS_BOARD
- if (st.counter_z > st.exec_block->step_event_count) {
- st.step_outbits[Z_AXIS] |= (1<step_event_count;
- if (st.exec_block->direction_bits[Z_AXIS] & (1< st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_3] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_3] & (1< 3
+ #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ st.counter_4 += st.steps[AXIS_4];
+ #else
+ st.counter_4 += st.exec_block->steps[AXIS_4];
+ #endif
+ if (st.counter_4 > st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_4] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_4] & (1< st.exec_block->step_event_count) {
- st.step_outbits |= (1<step_event_count;
- if (st.exec_block->direction_bits & (1< 3
+ #if N_AXIS > 4
+ #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ st.counter_5 += st.steps[AXIS_5];
+ #else
+ st.counter_5 += st.exec_block->steps[AXIS_5];
+ #endif
+ if (st.counter_5 > st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_5] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_5] & (1< 4
+ #if N_AXIS > 5
+ #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
+ st.counter_6 += st.steps[AXIS_6];
+ #else
+ st.counter_6 += st.exec_block->steps[AXIS_6];
+ #endif
+ if (st.counter_6 > st.exec_block->step_event_count) {
+ st.step_outbits[AXIS_6] |= (1<step_event_count;
+ if (st.exec_block->direction_bits[AXIS_6] & (1< 5
// During a homing cycle, lock out and prevent desired axes from moving.
- #ifdef DEFAULTS_RAMPS_BOARD
- for (i = 0; i < N_AXIS; i++)
+ for (i = 0; i < N_AXIS; i++)
if (sys.state == STATE_HOMING) { st.step_outbits[i] &= sys.homing_axis_lock[i]; }
- #else
- if (sys.state == STATE_HOMING) { st.step_outbits &= sys.homing_axis_lock; }
- #endif // Ramps Board
st.step_count--; // Decrement step events count
if (st.step_count == 0) {
// Segment is complete. Discard current segment and advance segment indexing.
st.exec_segment = NULL;
if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
}
- #ifdef DEFAULTS_RAMPS_BOARD
- for (i = 0; i < N_AXIS; i++)
- st.step_outbits[i] ^= step_port_invert_mask[i]; // Apply step port invert mask
- #else
- st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
- #endif // Ramps Board
+ for (i = 0; i < N_AXIS; i++)
+ st.step_outbits[i] ^= step_port_invert_mask[i]; // Apply step port invert mask
busy = false;
}
@@ -561,13 +607,18 @@ ISR(TIMER1_COMPA_vect)
ISR(TIMER0_OVF_vect)
{
// Reset stepping pins (leave the direction pins)
- #ifdef DEFAULTS_RAMPS_BOARD
- STEP_PORT(0) = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | step_port_invert_mask[0];
- STEP_PORT(1) = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | step_port_invert_mask[1];
- STEP_PORT(2) = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | step_port_invert_mask[2];
- #else
- STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK);
- #endif // Ramps Board
+ STEP_PORT(0) = (STEP_PORT(0) & ~(1 << STEP_BIT(0))) | step_port_invert_mask[0];
+ STEP_PORT(1) = (STEP_PORT(1) & ~(1 << STEP_BIT(1))) | step_port_invert_mask[1];
+ STEP_PORT(2) = (STEP_PORT(2) & ~(1 << STEP_BIT(2))) | step_port_invert_mask[2];
+ #if N_AXIS > 3
+ STEP_PORT(3) = (STEP_PORT(3) & ~(1 << STEP_BIT(3))) | step_port_invert_mask[3];
+ #endif
+ #if N_AXIS > 4
+ STEP_PORT(4) = (STEP_PORT(4) & ~(1 << STEP_BIT(4))) | step_port_invert_mask[4];
+ #endif
+ #if N_AXIS > 5
+ STEP_PORT(5) = (STEP_PORT(5) & ~(1 << STEP_BIT(5))) | step_port_invert_mask[5];
+ #endif
TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed.
}
#ifdef STEP_PULSE_DELAY
@@ -578,13 +629,18 @@ ISR(TIMER0_OVF_vect)
// st_wake_up() routine.
ISR(TIMER0_COMPA_vect)
{
- #ifdef DEFAULTS_RAMPS_BOARD
- STEP_PORT(0) = st.step_bits[0]; // Begin step pulse.
- STEP_PORT(1) = st.step_bits[1]; // Begin step pulse.
- STEP_PORT(2) = st.step_bits[2]; // Begin step pulse.
- #else
- STEP_PORT = st.step_bits; // Begin step pulse.
- #endif // Ramps Board
+ STEP_PORT(0) = st.step_bits[0]; // Begin step pulse.
+ STEP_PORT(1) = st.step_bits[1]; // Begin step pulse.
+ STEP_PORT(2) = st.step_bits[2]; // Begin step pulse.
+ #if N_AXIS > 3
+ STEP_PORT(3) = st.step_bits[3]; // Begin step pulse.
+ #endif
+ #if N_AXIS > 4
+ STEP_PORT(4) = st.step_bits[4]; // Begin step pulse.
+ #endif
+ #if N_AXIS > 5
+ STEP_PORT(5) = st.step_bits[5]; // Begin step pulse.
+ #endif
}
#endif
@@ -593,28 +649,20 @@ ISR(TIMER0_OVF_vect)
void st_generate_step_dir_invert_masks()
{
uint8_t idx;
- #ifdef DEFAULTS_RAMPS_BOARD
- for (idx=0; idx 3
+ STEP_PORT(3) = (STEP_PORT(3) & ~(1 << STEP_BIT(3))) | step_port_invert_mask[3];
+ DIRECTION_PORT(3) = (DIRECTION_PORT(3) & ~(1 << DIRECTION_BIT(3))) | dir_port_invert_mask[3];
+ #endif
+ #if N_AXIS > 4
+ STEP_PORT(4) = (STEP_PORT(4) & ~(1 << STEP_BIT(4))) | step_port_invert_mask[4];
+ DIRECTION_PORT(4) = (DIRECTION_PORT(4) & ~(1 << DIRECTION_BIT(4))) | dir_port_invert_mask[4];
+ #endif
+ #if N_AXIS > 5
+ STEP_PORT(5) = (STEP_PORT(5) & ~(1 << STEP_BIT(5))) | step_port_invert_mask[5];
+ DIRECTION_PORT(5) = (DIRECTION_PORT(5) & ~(1 << DIRECTION_BIT(5))) | dir_port_invert_mask[5];
+ #endif
}
@@ -657,23 +709,44 @@ void st_reset()
void stepper_init()
{
// Configure step and direction interface pins
- #ifdef DEFAULTS_RAMPS_BOARD
- STEP_DDR(0) |= 1< 3
+ STEP_DDR(3) |= 1< 4
+ STEP_DDR(4) |= 1< 5
+ STEP_DDR(5) |= 1< 3
+ STEPPER_DISABLE_DDR(3) |= 1< 4
+ STEPPER_DISABLE_DDR(4) |= 1< 5
+ STEPPER_DISABLE_DDR(5) |= 1< 3
+ DIRECTION_DDR(3) |= 1< 4
+ DIRECTION_DDR(4) |= 1< 5
+ DIRECTION_DDR(5) |= 1<direction_bits[idx] = pl_block->direction_bits[idx];
- }
- #else
- st_prep_block->direction_bits = pl_block->direction_bits;
- #endif // Ramps Board
+ for (idx=0; idxdirection_bits[idx] = pl_block->direction_bits[idx];
+ }
#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
for (idx=0; idxsteps[idx] = (pl_block->steps[idx] << 1); }
@@ -833,47 +902,47 @@ void st_prep_buffer()
} else {
prep.current_speed = sqrt(pl_block->entry_speed_sqr);
}
-
+
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
- // spindle off.
+ // spindle off.
st_prep_block->is_pwm_rate_adjusted = false;
if (settings.flags & BITFLAG_LASER_MODE) {
- if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
+ if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
// Pre-compute inverse programmed rate to speed up PWM updating per step segment.
prep.inv_rate = 1.0/pl_block->programmed_rate;
- st_prep_block->is_pwm_rate_adjusted = true;
+ st_prep_block->is_pwm_rate_adjusted = true;
}
}
}
- /* ---------------------------------------------------------------------------------
- Compute the velocity profile of a new planner block based on its entry and exit
- speeds, or recompute the profile of a partially-completed planner block if the
- planner has updated it. For a commanded forced-deceleration, such as from a feed
- hold, override the planner velocities and decelerate to the target exit speed.
- */
- prep.mm_complete = 0.0; // Default velocity profile complete at 0.0mm from end of block.
- float inv_2_accel = 0.5/pl_block->acceleration;
- if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { // [Forced Deceleration to Zero Velocity]
- // Compute velocity profile parameters for a feed hold in-progress. This profile overrides
- // the planner block profile, enforcing a deceleration to zero speed.
- prep.ramp_type = RAMP_DECEL;
- // Compute decelerate distance relative to end of block.
- float decel_dist = pl_block->millimeters - inv_2_accel*pl_block->entry_speed_sqr;
- if (decel_dist < 0.0) {
- // Deceleration through entire planner block. End of feed hold is not in this block.
- prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
- } else {
- prep.mm_complete = decel_dist; // End of feed hold.
- prep.exit_speed = 0.0;
- }
- } else { // [Normal Operation]
- // Compute or recompute velocity profile parameters of the prepped planner block.
- prep.ramp_type = RAMP_ACCEL; // Initialize as acceleration ramp.
- prep.accelerate_until = pl_block->millimeters;
-
- float exit_speed_sqr;
- float nominal_speed;
+ /* ---------------------------------------------------------------------------------
+ Compute the velocity profile of a new planner block based on its entry and exit
+ speeds, or recompute the profile of a partially-completed planner block if the
+ planner has updated it. For a commanded forced-deceleration, such as from a feed
+ hold, override the planner velocities and decelerate to the target exit speed.
+ */
+ prep.mm_complete = 0.0; // Default velocity profile complete at 0.0mm from end of block.
+ float inv_2_accel = 0.5/pl_block->acceleration;
+ if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { // [Forced Deceleration to Zero Velocity]
+ // Compute velocity profile parameters for a feed hold in-progress. This profile overrides
+ // the planner block profile, enforcing a deceleration to zero speed.
+ prep.ramp_type = RAMP_DECEL;
+ // Compute decelerate distance relative to end of block.
+ float decel_dist = pl_block->millimeters - inv_2_accel*pl_block->entry_speed_sqr;
+ if (decel_dist < 0.0) {
+ // Deceleration through entire planner block. End of feed hold is not in this block.
+ prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
+ } else {
+ prep.mm_complete = decel_dist; // End of feed hold.
+ prep.exit_speed = 0.0;
+ }
+ } else { // [Normal Operation]
+ // Compute or recompute velocity profile parameters of the prepped planner block.
+ prep.ramp_type = RAMP_ACCEL; // Initialize as acceleration ramp.
+ prep.accelerate_until = pl_block->millimeters;
+
+ float exit_speed_sqr;
+ float nominal_speed;
if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
prep.exit_speed = exit_speed_sqr = 0.0; // Enforce stop at end of system motion.
} else {
@@ -882,9 +951,9 @@ void st_prep_buffer()
}
nominal_speed = plan_compute_profile_nominal_speed(pl_block);
- float nominal_speed_sqr = nominal_speed*nominal_speed;
- float intersect_distance =
- 0.5*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr));
+ float nominal_speed_sqr = nominal_speed*nominal_speed;
+ float intersect_distance =
+ 0.5*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr));
if (pl_block->entry_speed_sqr > nominal_speed_sqr) { // Only occurs during override reductions.
prep.accelerate_until = pl_block->millimeters - inv_2_accel*(pl_block->entry_speed_sqr-nominal_speed_sqr);
@@ -907,39 +976,39 @@ void st_prep_buffer()
prep.maximum_speed = nominal_speed;
prep.ramp_type = RAMP_DECEL_OVERRIDE;
}
- } else if (intersect_distance > 0.0) {
- if (intersect_distance < pl_block->millimeters) { // Either trapezoid or triangle types
- // NOTE: For acceleration-cruise and cruise-only types, following calculation will be 0.0.
- prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
- if (prep.decelerate_after < intersect_distance) { // Trapezoid type
- prep.maximum_speed = nominal_speed;
- if (pl_block->entry_speed_sqr == nominal_speed_sqr) {
- // Cruise-deceleration or cruise-only type.
- prep.ramp_type = RAMP_CRUISE;
- } else {
- // Full-trapezoid or acceleration-cruise types
- prep.accelerate_until -= inv_2_accel*(nominal_speed_sqr-pl_block->entry_speed_sqr);
- }
- } else { // Triangle type
- prep.accelerate_until = intersect_distance;
- prep.decelerate_after = intersect_distance;
- prep.maximum_speed = sqrt(2.0*pl_block->acceleration*intersect_distance+exit_speed_sqr);
- }
- } else { // Deceleration-only type
+ } else if (intersect_distance > 0.0) {
+ if (intersect_distance < pl_block->millimeters) { // Either trapezoid or triangle types
+ // NOTE: For acceleration-cruise and cruise-only types, following calculation will be 0.0.
+ prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
+ if (prep.decelerate_after < intersect_distance) { // Trapezoid type
+ prep.maximum_speed = nominal_speed;
+ if (pl_block->entry_speed_sqr == nominal_speed_sqr) {
+ // Cruise-deceleration or cruise-only type.
+ prep.ramp_type = RAMP_CRUISE;
+ } else {
+ // Full-trapezoid or acceleration-cruise types
+ prep.accelerate_until -= inv_2_accel*(nominal_speed_sqr-pl_block->entry_speed_sqr);
+ }
+ } else { // Triangle type
+ prep.accelerate_until = intersect_distance;
+ prep.decelerate_after = intersect_distance;
+ prep.maximum_speed = sqrt(2.0*pl_block->acceleration*intersect_distance+exit_speed_sqr);
+ }
+ } else { // Deceleration-only type
prep.ramp_type = RAMP_DECEL;
// prep.decelerate_after = pl_block->millimeters;
// prep.maximum_speed = prep.current_speed;
- }
- } else { // Acceleration-only type
- prep.accelerate_until = 0.0;
- // prep.decelerate_after = 0.0;
- prep.maximum_speed = prep.exit_speed;
- }
- }
-
+ }
+ } else { // Acceleration-only type
+ prep.accelerate_until = 0.0;
+ // prep.decelerate_after = 0.0;
+ prep.maximum_speed = prep.exit_speed;
+ }
+ }
+
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); // Force update whenever updating block.
}
-
+
// Initialize new segment
segment_t *prep_segment = &segment_buffer[segment_buffer_head];
@@ -1048,16 +1117,16 @@ void st_prep_buffer()
/* -----------------------------------------------------------------------------------
Compute spindle speed PWM output for step segment
*/
-
+
if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) {
float rpm = pl_block->spindle_speed;
- // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
+ // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); }
// If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
// but this would be instantaneous only and during a motion. May not matter at all.
prep.current_spindle_pwm = spindle_compute_pwm_value(rpm);
- } else {
+ } else {
sys.spindle_speed = 0.0;
prep.current_spindle_pwm = SPINDLE_PWM_OFF_VALUE;
}
@@ -1065,7 +1134,7 @@ void st_prep_buffer()
}
prep_segment->spindle_pwm = prep.current_spindle_pwm; // Reload segment PWM value
-
+
/* -----------------------------------------------------------------------------------
Compute segment step rate, steps to execute, and apply necessary rate corrections.
NOTE: Steps are computed by direct scalar conversion of the millimeter distance
diff --git a/grbl/stepper.h b/grbl/stepper.h
index b552d542a..90591ec26 100644
--- a/grbl/stepper.h
+++ b/grbl/stepper.h
@@ -2,6 +2,7 @@
stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
Copyright (c) 2009-2011 Simen Svale Skogsrud
diff --git a/grbl/system.c b/grbl/system.c
index 59790ebfc..7f39977f3 100644
--- a/grbl/system.c
+++ b/grbl/system.c
@@ -2,6 +2,7 @@
system.c - Handles system level commands and real-time processes
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -67,10 +68,10 @@ ISR(CONTROL_INT_vect)
} else if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {
bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
} else if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {
- bit_true(sys_rt_exec_state, EXEC_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);
- }
+ }
}
}
@@ -121,7 +122,7 @@ uint8_t system_execute_line(char *line)
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':
+ case '$': case 'G': case 'C': case 'X': case 'D':
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
switch( line[1] ) {
case '$' : // Prints Grbl settings
@@ -154,6 +155,15 @@ uint8_t system_execute_line(char *line)
// Don't run startup script. Prevents stored moves in startup from causing accidents.
} // Otherwise, no effect.
break;
+ case 'D' : // Show digital input / output status
+ if ( line[2] != 0 ) {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ else {
+ uint8_t dg_state = digital_get_state();
+ report_digital_status(dg_state);
+ }
+ break;
}
break;
default :
@@ -173,12 +183,75 @@ uint8_t system_execute_line(char *line)
#ifdef HOMING_SINGLE_AXIS_COMMANDS
} else if (line[3] == 0) {
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;
+ case 'X': mc_homing_cycle(axis_X_mask); break;
+ case 'Y': mc_homing_cycle(axis_Y_mask); break;
+ case 'Z': mc_homing_cycle(axis_Z_mask); break;
+ case 'A':
+ if (axis_A_mask != 0) {
+ mc_homing_cycle(axis_A_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'B':
+ if (axis_B_mask != 0) {
+ mc_homing_cycle(axis_B_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'C':
+ if (axis_C_mask != 0) {
+ mc_homing_cycle(axis_C_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'U':
+ if (axis_U_mask != 0) {
+ mc_homing_cycle(axis_U_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'V':
+ if (axis_V_mask != 0) {
+ mc_homing_cycle(axis_V_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'W':
+ if (axis_W_mask != 0) {
+ mc_homing_cycle(axis_W_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'D':
+ if (axis_D_mask != 0) {
+ mc_homing_cycle(axis_D_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'E':
+ if (axis_E_mask != 0) {
+ mc_homing_cycle(axis_E_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
+ case 'H':
+ if (axis_H_mask != 0) {
+ mc_homing_cycle(axis_H_mask);
+ } else {
+ return(STATUS_INVALID_STATEMENT);
+ }
+ break;
default: return(STATUS_INVALID_STATEMENT);
}
- #endif
+ #endif // HOMING_SINGLE_AXIS_COMMANDS
} else { return(STATUS_INVALID_STATEMENT); }
if (!sys.abort) { // Execute startup scripts after successful homing.
sys.state = STATE_IDLE; // Set to IDLE when complete.
@@ -282,9 +355,9 @@ float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx)
{
float pos;
#ifdef COREXY
- if (idx==X_AXIS) {
+ if (idx==AXIS_1) {
pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
- } else if (idx==Y_AXIS) {
+ } else if (idx==AXIS_2) {
pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
} else {
pos = steps[idx]/settings.steps_per_mm[idx];
@@ -324,18 +397,21 @@ uint8_t system_check_travel_limits(float *target)
{
uint8_t idx;
for (idx=0; idx -settings.max_travel[idx]) { return(true); }
- } else {
+ // Ignore soft limit if AXIS_MAX_TRAVEL == 0 (parameter $130 to $135)
+ if (settings.max_travel[idx] != 0) {
+ #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); }
- }
- #else
- // NOTE: max_travel is stored as negative
- if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { return(true); }
- #endif
+ #endif
+ }
}
return(false);
}
diff --git a/grbl/system.h b/grbl/system.h
index 7060f2147..b17e751ad 100644
--- a/grbl/system.h
+++ b/grbl/system.h
@@ -2,6 +2,7 @@
system.h - Header for system level commands and real-time processes
Part of Grbl
+ Copyright (c) 2017-2022 Gauthier Briere
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
Grbl is free software: you can redistribute it and/or modify
@@ -28,25 +29,27 @@
// 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 1
+#define EXEC_CYCLE_START bit(1) // bitmask 00000010 2
+#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100 4
+#define EXEC_FEED_HOLD bit(3) // bitmask 00001000 8
+#define EXEC_RESET bit(4) // bitmask 00010000 16
+#define EXEC_SAFETY_DOOR bit(5) // bitmask 00100000 32
+#define EXEC_MOTION_CANCEL bit(6) // bitmask 01000000 64
+#define EXEC_SLEEP bit(7) // bitmask 10000000 128
// 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_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_TRAVEL 10
+#define EXEC_ALARM_SERIAL_RX_OVERFLOW 11
// 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.
@@ -95,10 +98,10 @@
// 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_END_MOTION bit(0) // 00000001 1
+#define STEP_CONTROL_EXECUTE_HOLD bit(1) // 00000010 2
+#define STEP_CONTROL_EXECUTE_SYS_MOTION bit(2) // 00000100 4
+#define STEP_CONTROL_UPDATE_SPINDLE_PWM bit(3) // 00001000 8
// Define control pin index for Grbl internal use. Pin maps may change, but these values don't.
#define N_CONTROL_PIN 4
@@ -118,16 +121,12 @@
// 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 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.
- #ifdef DEFAULTS_RAMPS_BOARD
- uint8_t homing_axis_lock[N_AXIS]; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
- #else
- uint8_t homing_axis_lock; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
- #endif
+ uint8_t homing_axis_lock[N_AXIS]; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
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
@@ -138,6 +137,9 @@ typedef struct {
uint8_t override_ctrl; // Tracks override control states.
#endif
float spindle_speed;
+ #ifdef USE_OUTPUT_PWM
+ float output_volts; // GBGB TODO: Implémenter de la même manière que spindle_speed...
+ #endif
} system_t;
extern system_t sys;
@@ -150,7 +152,19 @@ extern volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag
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 uint8_t axis_X_mask; // Global mask for axis X bits
+extern uint8_t axis_Y_mask; // Global mask for axis Y bits
+extern uint8_t axis_Z_mask; // Global mask for axis Z bits
+extern uint8_t axis_A_mask; // Global mask for axis A bits
+extern uint8_t axis_B_mask; // Global mask for axis B bits
+extern uint8_t axis_C_mask; // Global mask for axis C bits
+extern uint8_t axis_U_mask; // Global mask for axis A bits
+extern uint8_t axis_V_mask; // Global mask for axis B bits
+extern uint8_t axis_W_mask; // Global mask for axis C bits
+extern uint8_t axis_D_mask; // Global mask for axis A bits
+extern uint8_t axis_E_mask; // Global mask for axis B bits
+extern uint8_t axis_H_mask; // Global mask for axis C bits
+extern unsigned char axis_name[N_AXIS]; // Global table of axis names
#ifdef DEBUG
#define EXEC_DEBUG_REPORT bit(0)
extern volatile uint8_t sys_rt_exec_debug;