diff --git a/Grbl_Esp32/src/Limits.cpp b/Grbl_Esp32/src/Limits.cpp index 89e08b34..f47c154b 100644 --- a/Grbl_Esp32/src/Limits.cpp +++ b/Grbl_Esp32/src/Limits.cpp @@ -197,7 +197,7 @@ static void limits_go_home(uint8_t cycle_mask, uint32_t n_locate_cycles) { } homing_rate = float(sqrt(homing_rate)); // Magnitude of homing rate vector - sys.homing_axis_lock = axislock; + config->_axes->release_all_motors(); // Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle. pl_data->feed_rate = homing_rate; @@ -209,8 +209,9 @@ static void limits_go_home(uint8_t cycle_mask, uint32_t n_locate_cycles) { do { if (approach) { // Check limit state. Lock out cycle axes when they change. - bit_false(axislock, limits_check(axislock)); - sys.homing_axis_lock = axislock; + uint32_t limitedAxes = limits_check(axislock); + config->_axes->stop_motors(limitedAxes); + bit_false(axislock, limitedAxes); } Stepper::prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us. diff --git a/Grbl_Esp32/src/Machine/Axes.cpp b/Grbl_Esp32/src/Machine/Axes.cpp index e108023f..ceb52b29 100644 --- a/Grbl_Esp32/src/Machine/Axes.cpp +++ b/Grbl_Esp32/src/Machine/Axes.cpp @@ -79,7 +79,8 @@ namespace Machine { // use this to tell all the motors what the current homing mode is // They can use this to setup things like Stall - uint8_t Axes::set_homing_mode(uint8_t homing_mask, bool isHoming) { + uint32_t Axes::set_homing_mode(uint8_t homing_mask, bool isHoming) { + release_all_motors(); // On homing transitions, cancel all motor lockouts uint8_t can_home = 0; for (uint8_t axis = X_AXIS; axis < _numberAxis; axis++) { @@ -103,7 +104,13 @@ namespace Machine { return can_home; } + void Axes::release_all_motors() { _motorLockoutMask = 0xffffffff; } + void Axes::stop_motors(uint32_t mask) { bit_false(_motorLockoutMask, mask); } + void IRAM_ATTR Axes::step(uint8_t step_mask, uint8_t dir_mask) { + // Do not step motors that are locked out during homing + step_mask &= _motorLockoutMask; + auto n_axis = _numberAxis; //log_info("motors_set_direction_pins:0x%02X", onMask); diff --git a/Grbl_Esp32/src/Machine/Axes.h b/Grbl_Esp32/src/Machine/Axes.h index 9b3f664c..d38b6d3c 100644 --- a/Grbl_Esp32/src/Machine/Axes.h +++ b/Grbl_Esp32/src/Machine/Axes.h @@ -31,6 +31,10 @@ namespace Machine { bool _switchedStepper = false; + // During homing, this is used to stop stepping on motors that have + // reached their limit switches, by clearing bits in the mask. + uint32_t _motorLockoutMask = 0; + public: Axes(); @@ -82,12 +86,16 @@ namespace Machine { void init(); void read_settings(); // more like 'after read settings, before init'. Oh well... + // These are used during homing cycles. // The return value is a bitmask of axes that can home - uint8_t set_homing_mode(uint8_t homing_mask, bool isHoming); - void set_disable(int axis, bool disable); - void set_disable(bool disable); - void step(uint8_t step_mask, uint8_t dir_mask); - void unstep(); + uint32_t set_homing_mode(uint8_t homing_mask, bool isHoming); + void release_all_motors(); + void stop_motors(uint32_t motor_mask); + + void set_disable(int axis, bool disable); + void set_disable(bool disable); + void step(uint8_t step_mask, uint8_t dir_mask); + void unstep(); // Configuration helpers: void group(Configuration::HandlerBase& handler) override; diff --git a/Grbl_Esp32/src/Machine/LimitPin.cpp b/Grbl_Esp32/src/Machine/LimitPin.cpp new file mode 100644 index 00000000..2e3b5074 --- /dev/null +++ b/Grbl_Esp32/src/Machine/LimitPin.cpp @@ -0,0 +1,114 @@ +#include "LimitPin.h" +#include "Axes.h" +#include "MachineConfig.h" // config + +#include "../NutsBolts.h" // bitnum_true etc +#include "../MotionControl.h" // mc_reset +#include "../Limits.h" +#include "../System.h" // sys_rt_exec_alarm + +namespace Machine { + LimitPin::LimitPin(Pin& pin, int axis, int gang, int direction, bool& pHardLimits) : + _axis(axis), _gang(gang), _value(false), _pHardLimits(pHardLimits), _pin(pin) { + String sDir; + // Select one or two bitmask variables to receive the switch data + switch (direction) { + case 1: + _posLimits = &Axes::posLimitMask; + _negLimits = nullptr; + sDir = "Pos"; + break; + case -1: + _posLimits = nullptr; + _negLimits = &Axes::negLimitMask; + sDir = "Neg"; + break; + case 0: + _posLimits = &Axes::posLimitMask; + _negLimits = &Axes::negLimitMask; + sDir = "All"; + break; + default: // invalid + _negLimits = nullptr; + _posLimits = nullptr; + _pHardLimits = false; + break; + } + // Set a bitmap with bits to represent the axis and which motors are affected, + // and construct a legend string like "Y Axis Limit" or "Y Axis Gang0 Limit". + // The bitmap looks like CBAZYXcbazyx where gang0 motors are in the lower + // bits and gang1 in the upper bits. If both gangs are affected, there is + // a bit set in both the upper and lower groups. + switch (gang) { + case 0: + _bitmask = 1; // Set bit as for x axis gang 0 + _legend = " Gang0"; + break; + case 1: + _bitmask = 1 << MAX_N_AXIS; // Set bit as for X axis gang 1 + _legend = " Gang1"; + break; + case -1: // Axis level switch - set both bits + _bitmask = (1 << MAX_N_AXIS) | 1; + _legend = ""; + break; + default: + break; + } + _bitmask <<= axis; // Shift the bits into position + _legend = String(config->_axes->axisName(axis)) + " Axis" + _legend + " " + sDir + " Limit"; + } + + void IRAM_ATTR LimitPin::handleISR() { + bool pinState = _pin.read(); + _value = _pin.read(); + if (_value) { + if (_posLimits != nullptr) { + bit_true(*_posLimits, _bitmask); + } + if (_negLimits != nullptr) { + bit_true(*_negLimits, _bitmask); + } + } else { + if (_posLimits != nullptr) { + bit_false(*_posLimits, _bitmask); + } + if (_negLimits != nullptr) { + bit_false(*_negLimits, _bitmask); + } + } + if (sys.state != State::Alarm && sys.state != State::ConfigAlarm && sys.state != State::Homing) { + if (_pHardLimits && sys_rt_exec_alarm == ExecAlarm::None) { +#if 0 + + if (config->_softwareDebounceMs) { + // send a message to wakeup the task that rechecks the switches after a small delay + int evt; + xQueueSendFromISR(limit_sw_queue, &evt, NULL); + return; + } +#endif + + // log_debug("Hard limits"); // This might not work from ISR context + mc_reset(); // Initiate system kill. + sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event + } + } + } + + void LimitPin::init() { + if (_pin.undefined()) { + return; + } + bitnum_true(Axes::limitMask, _axis); + _pin.report(_legend.c_str()); + auto attr = Pin::Attr::Input | Pin::Attr::ISR; + if (_pin.capabilities().has(Pins::PinCapabilities::PullUp)) { + attr = attr | Pin::Attr::PullUp; + } + _pin.setAttr(attr); + _pin.attachInterrupt(this, CHANGE); + } + + LimitPin::~LimitPin() { _pin.detachInterrupt(); } +} diff --git a/Grbl_Esp32/src/Machine/LimitPin.h b/Grbl_Esp32/src/Machine/LimitPin.h new file mode 100644 index 00000000..dd53b760 --- /dev/null +++ b/Grbl_Esp32/src/Machine/LimitPin.h @@ -0,0 +1,36 @@ +#pragma once + +#include "../Pin.h" +#include // IRAM_ATTR + +namespace Machine { + class LimitPin { + private: + int _axis; + int _gang; + + bool _value = 0; + uint32_t _bitmask = 0; + + // _pHardLimits is a reference so the shared variable at the + // Endstops level can be changed at runtime to control the + // limit behavior dynamically. + bool& _pHardLimits; + volatile uint32_t* _posLimits = nullptr; + volatile uint32_t* _negLimits = nullptr; + + void IRAM_ATTR handleISR(); + + public: + LimitPin(Pin& pin, int axis, int gang, int direction, bool& phardLimits); + + Pin& _pin; + + String _legend; + + void init(); + bool get() { return _value; } + + ~LimitPin(); + }; +} diff --git a/Grbl_Esp32/src/Stepper.cpp b/Grbl_Esp32/src/Stepper.cpp index 783ca7e9..3af95a88 100644 --- a/Grbl_Esp32/src/Stepper.cpp +++ b/Grbl_Esp32/src/Stepper.cpp @@ -269,10 +269,6 @@ void IRAM_ATTR Stepper::pulse_func() { } } - // During a homing cycle, lock out and prevent desired axes from moving. - if (sys.state == State::Homing) { - st.step_outbits &= sys.homing_axis_lock; - } st.step_count--; // Decrement step events count if (st.step_count == 0) { // Segment is complete. Discard current segment and advance segment indexing.