diff --git a/Grbl_Esp32/src/I2SOut.cpp b/Grbl_Esp32/src/I2SOut.cpp index f0ec2f94..d5ff116d 100644 --- a/Grbl_Esp32/src/I2SOut.cpp +++ b/Grbl_Esp32/src/I2SOut.cpp @@ -503,7 +503,7 @@ static void IRAM_ATTR i2sOutTask(void* parameter) { } else if (i2s_out_pulser_status == WAITING) { if (dma_desc->qe.stqe_next == NULL) { // Tail of the DMA descriptor found - // I2S TX module has alrewdy stopped by ISR + // I2S TX module has already stopped by ISR i2s_out_stop(); i2s_clear_o_dma_buffers(0); // 0 for static I2S control mode (right ch. data is always 0) // You need to set the status before calling i2s_out_start() @@ -546,6 +546,7 @@ void IRAM_ATTR i2s_out_delay() { } else { // Just wait until the data now registered in the DMA descripter // is reflected in the I2S TX module via FIFO. + // XXX perhaps just wait until I2SO.conf1.tx_start == 0 delay(I2S_OUT_DELAY_MS); } I2S_OUT_PULSER_EXIT_CRITICAL(); diff --git a/Grbl_Esp32/src/Machine/Axes.cpp b/Grbl_Esp32/src/Machine/Axes.cpp index 5caa2192..aa5a481a 100644 --- a/Grbl_Esp32/src/Machine/Axes.cpp +++ b/Grbl_Esp32/src/Machine/Axes.cpp @@ -133,6 +133,7 @@ namespace Machine { auto wait_direction = config->_directionDelayMicroSeconds; if (wait_direction > 0) { + // stepping->turnaround(wait_direction); // Stepper drivers need some time between changing direction and doing a pulse. switch (config->_stepType) { case stepper_id_t::ST_I2S_STREAM: @@ -213,6 +214,35 @@ namespace Machine { return SIZE_MAX; } + // Wait for motion to complete; the axes can still be moving + // after the data has been sent to the stepping engine, due + // to queuing delays. + void Axes::synchronize() { + if (config->_stepType == ST_I2S_STREAM) { + // XXX instead of a delay, we could sense when the DMA and + // FIFO have drained. It might be as simple as waiting for + // I2SO.conf1.tx_start == 0, while yielding. + delay_ms(I2S_OUT_DELAY_MS); + } + } + void Axes::beginLowLatency() { + _switchedStepper = config->_stepType == ST_I2S_STREAM; + if (_switchedStepper) { + config->_stepType = ST_I2S_STATIC; + } + } + void Axes::endLowLatency() { + if (_switchedStepper) { + if (i2s_out_get_pulser_status() != PASSTHROUGH) { + // Called during streaming. Stop streaming. + debug_serial("Stop the I2S streaming and switch to the passthrough mode."); + i2s_out_set_passthrough(); + i2s_out_delay(); // Wait for a change in mode. + } + config->_stepType = ST_I2S_STREAM; + } + } + // Configuration helpers: void Axes::group(Configuration::HandlerBase& handler) { diff --git a/Grbl_Esp32/src/Machine/Axes.h b/Grbl_Esp32/src/Machine/Axes.h index 7d72fb4f..d470fb1a 100644 --- a/Grbl_Esp32/src/Machine/Axes.h +++ b/Grbl_Esp32/src/Machine/Axes.h @@ -30,6 +30,8 @@ namespace Machine { static const int MAX_NUMBER_AXIS = 6; static constexpr const char* _names = "XYZABC"; + bool _switchedStepper = false; + public: Axes(); @@ -65,6 +67,10 @@ namespace Machine { return false; } + void synchronize(); // Wait for motion to complete + void beginLowLatency(); + void endLowLatency(); + // These are used for setup and to talk to the motors as a group. void init(); void read_settings(); // more like 'after read settings, before init'. Oh well... diff --git a/Grbl_Esp32/src/MotionControl.cpp b/Grbl_Esp32/src/MotionControl.cpp index 4e3de13f..11ef29b0 100644 --- a/Grbl_Esp32/src/MotionControl.cpp +++ b/Grbl_Esp32/src/MotionControl.cpp @@ -274,12 +274,6 @@ bool mc_dwell(int32_t milliseconds) { return delay_msec(milliseconds, DwellMode::Dwell); } -inline void RESTORE_STEPPER(int save_stepper) { - if (save_stepper == ST_I2S_STREAM && config->_stepType != ST_I2S_STREAM) { - Stepper::switch_mode(ST_I2S_STREAM); /* Put the stepper back on. */ - } -} - // Perform homing cycle to locate and set machine zero. Only '$H' executes this command. // NOTE: There should be no motions in the buffer and Grbl must be in an idle state before // executing the homing cycle. This prevents incorrect buffered plans after homing. @@ -337,10 +331,7 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par int save_stepper = config->_stepType; /* remember the stepper */ - // Switch stepper mode to the I2S static (realtime mode) - if (save_stepper == ST_I2S_STREAM) { - Stepper::switch_mode(ST_I2S_STATIC); /* Change the stepper to reduce the delay for accurate probing. */ - } + config->_axes->beginLowLatency(); // Initialize probing control variables bool is_probe_away = bit_istrue(parser_flags, GCParserProbeIsAway); @@ -352,8 +343,8 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par if (config->_probe->tripped()) { sys_rt_exec_alarm = ExecAlarm::ProbeFailInitial; protocol_execute_realtime(); - RESTORE_STEPPER(save_stepper); // Switch the stepper mode to the previous mode - return GCUpdatePos::None; // Nothing else to do but bail. + config->_axes->endLowLatency(); + return GCUpdatePos::None; // Nothing else to do but bail. } // Setup and queue probing motion. Auto cycle-start should not start the cycle. info_serial("Found"); @@ -365,13 +356,12 @@ GCUpdatePos mc_probe_cycle(float* target, plan_line_data_t* pl_data, uint8_t par do { protocol_execute_realtime(); if (sys.abort) { - RESTORE_STEPPER(save_stepper); // Switch the stepper mode to the previous mode - return GCUpdatePos::None; // Check for system abort + config->_axes->endLowLatency(); + return GCUpdatePos::None; // Check for system abort } } while (sys.state != State::Idle); - // Switch the stepper mode to the previous mode - RESTORE_STEPPER(save_stepper); + config->_axes->endLowLatency(); // Probing cycle complete! // Set state variables and error out, if the probe failed and cycle with error is enabled. diff --git a/Grbl_Esp32/src/Motors/StandardStepper.cpp b/Grbl_Esp32/src/Motors/StandardStepper.cpp index 4c5b3764..4f6fbc8b 100644 --- a/Grbl_Esp32/src/Motors/StandardStepper.cpp +++ b/Grbl_Esp32/src/Motors/StandardStepper.cpp @@ -57,6 +57,7 @@ namespace Motors { _dir_pin.setAttr(Pin::Attr::Output); + // stepping->init(_step_pin); if (config->_stepType == ST_RMT) { rmtConfig.rmt_mode = RMT_MODE_TX; rmtConfig.clk_div = 20; diff --git a/Grbl_Esp32/src/ProcessSettings.cpp b/Grbl_Esp32/src/ProcessSettings.cpp index 7ff701d5..102fad4a 100644 --- a/Grbl_Esp32/src/ProcessSettings.cpp +++ b/Grbl_Esp32/src/ProcessSettings.cpp @@ -272,16 +272,11 @@ Error home(int cycle) { } sys.state = State::Homing; // Set system state variable - int save_stepper = config->_stepType; - if (save_stepper == ST_I2S_STREAM) { - Stepper::switch_mode(ST_I2S_STATIC); - } + config->_axes->beginLowLatency(); mc_homing_cycle(cycle); - if (save_stepper == ST_I2S_STREAM && config->_stepType != ST_I2S_STREAM) { - Stepper::switch_mode(ST_I2S_STREAM); - } + config->_axes->endLowLatency(); if (!sys.abort) { // Execute startup scripts after successful homing. sys.state = State::Idle; // Set to IDLE when complete. diff --git a/Grbl_Esp32/src/Stepper.cpp b/Grbl_Esp32/src/Stepper.cpp index 83e86cff..2de9d4d4 100644 --- a/Grbl_Esp32/src/Stepper.cpp +++ b/Grbl_Esp32/src/Stepper.cpp @@ -348,17 +348,19 @@ static void IRAM_ATTR pulse_func() { } } - auto pulseMicros = config->_pulseMicroSeconds; + // stepping->unStep(pulseMicros); + uint64_t endMicros; switch (config->_stepType) { case ST_I2S_STREAM: // Generate the number of pulses needed to span pulse_microseconds - i2s_out_push_sample(pulseMicros); + i2s_out_push_sample(config->_pulseMicroSeconds); config->_axes->unstep(); break; case ST_I2S_STATIC: case ST_TIMED: + endMicros = config->_pulseMicroSeconds + step_pulse_start_time; // wait for step pulse time to complete...some time expired during code above - while (esp_timer_get_time() - step_pulse_start_time < pulseMicros) { + while ((esp_timer_get_time() - endMicros) < 0) { NOP(); // spin here until time to turn off step } config->_axes->unstep(); @@ -373,6 +375,7 @@ void Stepper::init() { info_serial("Axis count %d", config->_axes->_numberAxis); info_serial("Step type:%s Pulse:%dus Dsbl Delay:%dus Dir Delay:%dus", + // stepping->name(), stepTypes[config->_stepType].name, config->_pulseMicroSeconds, config->_disableDelayMicroSeconds, @@ -382,25 +385,6 @@ void Stepper::init() { timerInit(); } -void Stepper::switch_mode(stepper_id_t new_stepper) { - debug_serial("Switch stepper: %s -> %s", stepTypes[config->_stepType].name, stepTypes[new_stepper].name); - if (config->_stepType == new_stepper) { - // do not need to change - return; - } - - if (config->_stepType == ST_I2S_STREAM) { - if (i2s_out_get_pulser_status() != PASSTHROUGH) { - // Called during streaming. Stop streaming. - debug_serial("Stop the I2S streaming and switch to the passthrough mode."); - i2s_out_set_passthrough(); - i2s_out_delay(); // Wait for a change in mode. - } - } - - config->_stepType = new_stepper; -} - // enabled. Startup init and limits call this function but shouldn't start the cycle. void Stepper::wake_up() { //info_serial("st_wake_up"); @@ -415,6 +399,7 @@ void Stepper::wake_up() { // Reset and clear stepper subsystem variables void Stepper::reset() { // Initialize stepper driver idle state. + // stepping->reset(); if (config->_stepType == ST_I2S_STREAM) { i2s_out_reset(); } @@ -930,6 +915,7 @@ float Stepper::get_realtime_rate() { // The argument is in units of ticks of the timer that generates ISRs static void IRAM_ATTR timerWritePeriod(uint16_t timerTicks) { + // stepping->setPeriod(uint16_t timerTicks); if (config->_stepType == ST_I2S_STREAM) { // 1 tick = fTimers / fStepperTimer // Pulse ISR is called for each tick of alarm_val. @@ -956,6 +942,7 @@ static void IRAM_ATTR timerInit() { } static void IRAM_ATTR timerStart() { + // stepping->start(); if (config->_stepType == ST_I2S_STREAM) { i2s_out_set_stepping(); } else { @@ -965,6 +952,7 @@ static void IRAM_ATTR timerStart() { } static void IRAM_ATTR timerStop() { + // stepping->stop(); if (config->_stepType == ST_I2S_STREAM) { i2s_out_set_passthrough(); } else if (stepTimer) {