2828#include "limits.h"
2929#include "report.h"
3030
31- #define HOMING_CYCLE_LINE_NUMBER MAX_LINE_NUMBER
31+ #define HOMING_ZERO_LINE_NUMBER (LINENUMBER_SPECIAL|0)
32+ #define HOMING_FINISHED_LINE_NUMBER (LINENUMBER_SPECIAL|1)
3233
3334#define HOMING_AXIS_SEARCH_SCALAR 1.1 // Axis search distance multiplier. Must be > 1.
3435
@@ -49,11 +50,6 @@ void limits_init()
4950 LIMIT_PORT |= (LIMIT_MASK ); // Enable internal pull-up resistors. Normal high operation.
5051 }
5152
52-
53- /* LIMIT_PCMSK &= ~LIMIT_MASK; // prevent spurious interrupts while configuring
54- PCICR |= LIMIT_INT; // Enable Pin Change Interrupt on correct port.
55- */
56-
5753 if (bit_istrue (settings .flags ,BITFLAG_HARD_LIMIT_ENABLE )) {
5854 limits_enable (LIMIT_MASK & HARDSTOP_MASK ,0 );
5955 } else {
@@ -81,62 +77,23 @@ void limits_disable()
8177 limits .active = 0 ;
8278}
8379
84- // This is the Limit Pin Change Interrupt, which handles the hard limit feature. A bouncing
85- // limit switch can cause a lot of problems, like false readings and multiple interrupt calls.
86- // If a switch is triggered at all, something bad has happened and treat it as such, regardless
87- // if a limit switch is being disengaged. It's impossible to reliably tell the state of a
88- // bouncing pin without a debouncing method. A simple software debouncing feature may be enabled
89- // through the config.h file, where an extra timer delays the limit pin read by several milli-
90- // seconds to help with, not fix, bouncing switches.
91- // NOTE: Do not attach an e-stop to the limit pins, because this interrupt is disabled during
92- // homing cycles and will not respond correctly. Upon user request or need, there may be a
93- // special pinout for an e-stop, but it is generally recommended to just directly connect
94- // your e-stop switch to the Arduino reset pin, since it is the most correct way to do this.
95- // Ignore limit switches if already in an alarm state or in-process of executing an alarm.
96- // When in the alarm state, Grbl should have been reset or will force a reset, so any pending
80+
81+ // Limit checking moved to stepper ISR.
82+ // limits_enable() sets limits.active and limits.expected flags.
83+ // stepper stops an axis whenever LIMIT_PIN&limits.active != limits.expected,
84+ // in this case, it also sets limits.homenext to signal homing routine to continue.
85+ // If not homing, it does a hard reset and sets the alarm.state
86+ // (See `must_stop` section of ISR TIMER1_COMPA_vect)
87+
88+ // TODO: do we need special handling if already in an alarm state or in-process of executing an alarm.
89+ // Old comments said:
90+ // Ignore limit switches When in the alarm state:
91+ // Grbl should have been reset or will force a reset, so any pending
9792 // moves in the planner and serial buffers are all cleared and newly sent blocks will be
9893 // locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
9994 // limit setting if their limits are constantly triggering after a reset and move their axes.
10095
10196
102- void check_limit_pins ()
103- {
104- uint8_t invert_mask = (bit_istrue (settings .flags ,BITFLAG_INVERT_LIMIT_PINS )) ? LIMIT_MASK : 0 ;
105- //sysflags.limit bits are set when limit is triggered
106- SYS_EXEC |= EXEC_LIMIT_REPORT ;
107- sysflags .limits = (LIMIT_PIN ^ invert_mask );
108-
109- if (sys .state & STATE_HOMING ) {
110- //clear axislock bits when limit toggled.
111- sysflags .homing_axis_lock &= (LIMIT_PIN >>LIMIT_BIT_SHIFT )^limit_approach ;
112- }
113- else if (sysflags .limits & LIMIT_MASK ) {
114- if (!(sys .state & STATE_ALARM )) {
115- if (bit_isfalse (SYS_EXEC ,EXEC_ALARM )) {
116- mc_reset (); // Initiate system kill.
117- SYS_EXEC |= (EXEC_ALARM | EXEC_CRIT_EVENT ); // Indicate hard limit critical event
118- }
119- }
120- }
121- }
122-
123- #ifndef ENABLE_SOFTWARE_DEBOUNCE
124- ISR (LIMIT_INT_vect ) // DEFAULT: Limit pin change interrupt process.
125- {
126- }
127- #else // OPTIONAL: Software debounce limit pin routine.
128- // Upon limit pin change, enable watchdog timer to create a short delay.
129- ISR (LIMIT_INT_vect ) {
130- if (!(WDTCSR & (1 <<WDIE ))) { WDTCSR |= (1 <<WDIE ); }
131- }
132- ISR (WDT_vect ) // Watchdog timer ISR
133- {
134- WDTCSR &= ~(1 <<WDIE ); // Disable watchdog timer.
135- check_limit_pins ();
136- }
137- #endif
138-
139-
14097// Homes the specified cycle axes, sets the machine position, and performs a pull-off motion after
14198// completing. Homing is a special motion case, which involves rapid uncontrolled stops to locate
14299// the trigger point of the limit switches. The rapid stops are handled by a system level axis lock
@@ -154,50 +111,46 @@ void limits_go_home(uint8_t cycle_mask)
154111 uint8_t n_cycle = (2 * N_HOMING_LOCATE_CYCLE + 1 );
155112 float target [N_AXIS ];
156113
114+ uint8_t flipped = settings .homing_dir_mask >>X_DIRECTION_BIT ; //assumes keyme configuration.
115+ //replace with an instance of `if (bitistrue(h_d_m,X_DIRECTION_BIT)) { flipped|=1<<X_AXIS;}`
116+ //for each axis if the bits line up differently
117+
157118 // Determine travel distance to the furthest homing switch based on user max travel settings.
158119 float min_seek_rate = 1e9 ; //arbitrary maximum=1km/s, will be reduced by axis setting below
159120 float max_travel = 0 ;
121+
160122 for (idx = 0 ; idx < N_AXIS ; idx ++ ){
161123 if (bit_istrue (cycle_mask ,bit (idx ))) {
162124 max_travel = max (max_travel ,settings .max_travel [idx ]);
163125 homing_rate = min (homing_rate ,settings .homing_seek_rate [idx ]);
164126 }
165127 }
166128 max_travel *= HOMING_AXIS_SEARCH_SCALAR ; // Ensure homing switches engaged by over-estimating max travel.
129+ max_travel += settings .homing_pulloff ;
167130 homing_rate = min_seek_rate ;
168-
131+
169132 plan_reset (); // Reset planner buffer to zero planner current position and to clear previous motions.
170-
133+
171134 do {
172-
173135 // Set target location and rate for active axes.
136+ // and reset homing axis locks based on cycle mask.
137+ uint8_t axislock = 0 ;
174138 uint8_t n_active_axis = 0 ;
175139 for (idx = 0 ; idx < N_AXIS ; idx ++ ) {
176140 if (bit_istrue (cycle_mask ,bit (idx ))) {
177141 n_active_axis ++ ;
178- if (!approach ) { target [idx ] = max_travel ; }
179- else { target [idx ] = - max_travel ; }
180- } else {
181- target [idx ] = 0.0 ;
182- }
142+ axislock |= (1 <<(X_STEP_BIT + idx )); //assumes axes are in bit order.
143+ if ((flipped & (1 <<idx ))^approach ) { target [idx ] = - max_travel ; }
144+ else { target [idx ] = max_travel ; }
145+ }
146+ else { target [idx ] = 0 ;
147+ }
183148 }
184- if (bit_istrue (settings .homing_dir_mask ,(1 <<X_DIRECTION_BIT ))) { target [X_AXIS ] = - target [X_AXIS ]; }
185- if (bit_istrue (settings .homing_dir_mask ,(1 <<Y_DIRECTION_BIT ))) { target [Y_AXIS ] = - target [Y_AXIS ]; }
186- if (bit_istrue (settings .homing_dir_mask ,(1 <<Z_DIRECTION_BIT ))) { target [Z_AXIS ] = - target [Z_AXIS ]; }
187- if (bit_istrue (settings .homing_dir_mask ,(1 <<C_DIRECTION_BIT ))) { target [C_AXIS ] = - target [Z_AXIS ]; }
188149
189150 homing_rate *= sqrt (n_active_axis ); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
151+ // homing_rate is reset each time through this loop, so it doesn't keep increasing
190152
191- // Reset homing axis locks based on cycle mask.
192- uint8_t axislock = 0 ;
193- if (bit_istrue (cycle_mask ,bit (X_AXIS ))) { axislock |= (1 <<X_STEP_BIT ); }
194- if (bit_istrue (cycle_mask ,bit (Y_AXIS ))) { axislock |= (1 <<Y_STEP_BIT ); }
195- if (bit_istrue (cycle_mask ,bit (Z_AXIS ))) { axislock |= (1 <<Z_STEP_BIT ); }
196- if (bit_istrue (cycle_mask ,bit (C_AXIS ))) { axislock |= (1 <<C_STEP_BIT ); }
197-
198- // axis_lock bit is high if axis is homing, a 0 prevents it from being moved in stepper.
199- sysflags .homing_axis_lock = axislock ;
200- limit_approach = approach ; //limit_approach bits is high if approaching limit switch
153+ limit_approach = approach ; //limit_approach bits is high if approaching limit switch
201154
202155 // Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
203156 #ifdef USE_LINE_NUMBERS
@@ -206,6 +159,7 @@ void limits_go_home(uint8_t cycle_mask)
206159 plan_buffer_line (target , homing_rate , false); // Bypass mc_line(). Directly plan homing motion.
207160 #endif
208161
162+ // axislock bit is high if axis is homing, so we only enable checking on moving axes.
209163 limits_enable (axislock ,~approach ); //expect 0 on approach (stop when 1). vice versa for pulloff
210164 limits .homenext = 0 ;
211165
@@ -224,7 +178,6 @@ void limits_go_home(uint8_t cycle_mask)
224178 protocol_execute_runtime ();
225179 return ;
226180 }
227-
228181 } while (!limits .homenext ); //stepper isr sets this when limit is hit
229182
230183 limits_disable ();
@@ -240,6 +193,11 @@ void limits_go_home(uint8_t cycle_mask)
240193
241194 } while (n_cycle -- > 0 );
242195
196+ //force report of known position for compare to zero.
197+ linenumber_insert (HOMING_ZERO_LINE_NUMBER );
198+ request_report_status (1 );
199+ protocol_execute_runtime ();
200+
243201 // The active cycle axes should now be homed and machine limits have been located. By
244202 // default, grbl defines machine space as all negative, as do most CNCs. Since limit switches
245203 // can be on either side of an axes, check and set axes machine zero appropriately. Also,
@@ -258,15 +216,15 @@ void limits_go_home(uint8_t cycle_mask)
258216 sys .position [idx ] = - settings .homing_pulloff * settings .steps_per_mm [idx ];
259217 target [idx ] = 0 ;
260218 }
261- if (settings .homing_pulloff == 0.0 ) { SYS_EXEC |=EXEC_STATUS_REPORT ; } //force report if we are not going to move
219+ if (settings .homing_pulloff == 0.0 ) {SYS_EXEC |=EXEC_STATUS_REPORT ; } //force report if we are not going to move TODO TEST
262220 } else { // Non-active cycle axis. Set target to not move during pull-off.
263221 target [idx ] = (float )sys .position [idx ]/settings .steps_per_mm [idx ];
264222 }
265223 }
266224 plan_sync_position (); // Sync planner position to current machine position for pull-off move.
267225
268226 #ifdef USE_LINE_NUMBERS
269- plan_buffer_line (target , min_seek_rate , false, HOMING_CYCLE_LINE_NUMBER ); // Bypass mc_line(). Directly plan motion.
227+ plan_buffer_line (target , min_seek_rate , false, HOMING_FINISHED_LINE_NUMBER ); // Bypass mc_line(). Directly plan motion.
270228 #else
271229 plan_buffer_line (target , min_seek_rate , false); // Bypass mc_line(). Directly plan motion.
272230 #endif
0 commit comments