1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-30 09:39:49 +02:00

Replace esp_delay_us() with ISR-friendly code in IRAM

This commit is contained in:
Mitch Bradley
2021-07-16 09:32:49 -10:00
parent 9506992f6e
commit ce7fffd6e4
8 changed files with 50 additions and 19 deletions

View File

@@ -24,6 +24,8 @@
// #define true 1 // #define true 1
#include <cstdint> #include <cstdint>
#include <esp_attr.h>
#include <xtensa/core-macros.h>
enum class DwellMode : uint8_t { enum class DwellMode : uint8_t {
Dwell = 0, // (Default: Must be zero) Dwell = 0, // (Default: Must be zero)
@@ -93,6 +95,9 @@ const float INCH_PER_MM = (0.0393701f);
// a pointer to the result variable. Returns true when it succeeds // a pointer to the result variable. Returns true when it succeeds
uint8_t read_float(const char* line, uint8_t* char_counter, float* float_ptr); uint8_t read_float(const char* line, uint8_t* char_counter, float* float_ptr);
// Blocking delay for very short time intervals
void delay_us(int32_t microseconds);
// Non-blocking delay function used for general operation and suspend features. // Non-blocking delay function used for general operation and suspend features.
bool delay_msec(int32_t milliseconds, DwellMode mode); bool delay_msec(int32_t milliseconds, DwellMode mode);
@@ -118,3 +123,38 @@ void swap(T& a, T& b) {
a = b; a = b;
b = c; b = c;
} }
// Short delays measured using the CPU cycle counter. There is a ROM
// routine "esp_delay_us(us)" that almost does what what we need,
// except that it is in ROM and thus dodgy for use from ISRs. We
// duplicate the esp_delay_us() here, but placed in IRAM, inlined,
// and factored so it can be used in different ways.
inline int32_t IRAM_ATTR getCpuTicks() {
return XTHAL_GET_CCOUNT();
}
extern uint32_t g_ticks_per_us_pro; // For CPU 0 - typically 240 MHz
extern uint32_t g_ticks_per_us_app; // For CPU 1 - typically 240 MHz
inline int32_t IRAM_ATTR usToCpuTicks(int32_t us) {
return us * g_ticks_per_us_pro;
}
inline int32_t IRAM_ATTR usToEndTicks(int32_t us) {
return getCpuTicks() + usToCpuTicks(us);
}
// At the usual ESP32 clock rate of 240MHz, the range of this is
// just under 18 seconds, but it really should be used only for
// short delays up to a few tens of microseconds.
inline void IRAM_ATTR spinUntil(int32_t endTicks) {
while ((XTHAL_GET_CCOUNT() - endTicks) < 0) {
asm volatile("nop");
}
}
inline void IRAM_ATTR delay_us(int32_t us) {
spinUntil(usToEndTicks(us));
}

View File

@@ -52,7 +52,7 @@ namespace Spindles {
} }
set_output(dev_speed); set_output(dev_speed);
set_enable(state != SpindleState::Disable); set_enable(state != SpindleState::Disable);
spinDelay(state, speed); spindleDelay(state, speed);
sys.report_ovr_counter = 0; // Set to report change immediately sys.report_ovr_counter = 0; // Set to report change immediately
} }

View File

@@ -112,7 +112,7 @@ namespace Spindles {
// converters on some boards. // converters on some boards.
set_output(dev_speed); set_output(dev_speed);
set_enable(state != SpindleState::Disable); set_enable(state != SpindleState::Disable);
spinDelay(state, speed); spindleDelay(state, speed);
sys.report_ovr_counter = 0; // Set to report change immediately sys.report_ovr_counter = 0; // Set to report change immediately
} }

View File

@@ -140,7 +140,7 @@ namespace Spindles {
// log_debug("rpm " << speed << " speed " << dev_speed); // This will spew quite a bit of data on your output // log_debug("rpm " << speed << " speed " << dev_speed); // This will spew quite a bit of data on your output
return dev_speed; return dev_speed;
} }
void Spindle::spinDelay(SpindleState state, SpindleSpeed speed) { void Spindle::spindleDelay(SpindleState state, SpindleSpeed speed) {
uint32_t up = 0, down = 0; uint32_t up = 0, down = 0;
switch (state) { switch (state) {
case SpindleState::Unknown: case SpindleState::Unknown:

View File

@@ -59,7 +59,7 @@ namespace Spindles {
static void switchSpindle(uint8_t new_tool, SpindleList spindles, Spindle*& spindle); static void switchSpindle(uint8_t new_tool, SpindleList spindles, Spindle*& spindle);
void spinDelay(SpindleState state, SpindleSpeed speed); void spindleDelay(SpindleState state, SpindleSpeed speed);
virtual void init() = 0; // not in constructor because this also gets called when $$ settings change virtual void init() = 0; // not in constructor because this also gets called when $$ settings change
// Used by Protocol.cpp to restore the state during a restart // Used by Protocol.cpp to restore the state during a restart

View File

@@ -345,7 +345,7 @@ namespace Spindles {
} }
} }
if (!supports_actual_speed()) { if (!supports_actual_speed()) {
spinDelay(state, speed); spindleDelay(state, speed);
} else { } else {
// _sync_dev_speed is set by a callback that handles // _sync_dev_speed is set by a callback that handles
// responses from periodic get_current_speed() requests. // responses from periodic get_current_speed() requests.
@@ -386,7 +386,7 @@ namespace Spindles {
} }
_syncing = false; _syncing = false;
// spinDelay() sets these when it is used // spindleDelay() sets these when it is used
_current_state = state; _current_state = state;
_current_speed = speed; _current_speed = speed;
} }

View File

@@ -73,13 +73,6 @@ namespace Machine {
_engine = I2S_STREAM; _engine = I2S_STREAM;
} }
} }
void IRAM_ATTR Stepping::spinDelay(int64_t start_time, uint32_t durationUs) {
int64_t endTime = start_time + durationUs;
while ((esp_timer_get_time() - endTime) < 0) {
NOP();
}
}
void IRAM_ATTR Stepping::waitPulse() { void IRAM_ATTR Stepping::waitPulse() {
uint64_t pulseEndTime; uint64_t pulseEndTime;
switch (_engine) { switch (_engine) {
@@ -90,7 +83,7 @@ namespace Machine {
case I2S_STATIC: case I2S_STATIC:
i2s_out_push(); i2s_out_push();
case TIMED: case TIMED:
spinDelay(_stepPulseStartTime, _pulseUsecs); spinUntil(_stepPulseEndTime);
break; break;
case RMT: case RMT:
// RMT generates the trailing edges in hardware // RMT generates the trailing edges in hardware
@@ -112,7 +105,7 @@ namespace Machine {
// If we are using GPIO stepping as opposed to RMT, record the // If we are using GPIO stepping as opposed to RMT, record the
// time that we turned on the direction pins so we can delay a bit. // time that we turned on the direction pins so we can delay a bit.
// If we are using RMT, we can't delay here. // If we are using RMT, we can't delay here.
spinDelay(esp_timer_get_time(), _directionDelayUsecs); delay_us(_directionDelayUsecs);
break; break;
case stepper_id_t::RMT: case stepper_id_t::RMT:
break; break;
@@ -126,7 +119,7 @@ namespace Machine {
break; break;
case stepper_id_t::I2S_STATIC: case stepper_id_t::I2S_STATIC:
case stepper_id_t::TIMED: case stepper_id_t::TIMED:
_stepPulseStartTime = esp_timer_get_time(); _stepPulseEndTime = usToEndTicks(_pulseUsecs);
break; break;
case stepper_id_t::RMT: case stepper_id_t::RMT:
break; break;

View File

@@ -35,9 +35,7 @@ namespace Machine {
static const int ticksPerMicrosecond = fStepperTimer / 1000000; static const int ticksPerMicrosecond = fStepperTimer / 1000000;
bool _switchedStepper = false; bool _switchedStepper = false;
int64_t _stepPulseStartTime; int32_t _stepPulseEndTime;
static void spinDelay(int64_t start_time, uint32_t duration);
public: public:
// Counts stepper ISR invocations. This variable can be inspected // Counts stepper ISR invocations. This variable can be inspected