|
|
|
@@ -37,9 +37,9 @@ typedef struct {
|
|
|
|
|
uint32_t steps[N_AXIS];
|
|
|
|
|
uint32_t step_event_count;
|
|
|
|
|
uint8_t direction_bits;
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
} st_block_t;
|
|
|
|
|
static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
|
|
|
|
|
|
|
|
|
@@ -51,14 +51,14 @@ typedef struct {
|
|
|
|
|
uint16_t n_step; // Number of step events to be executed for this segment
|
|
|
|
|
uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate.
|
|
|
|
|
uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment.
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
uint8_t amass_level; // Indicates AMASS level for the ISR to execute this segment
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
uint8_t prescaler; // Without AMASS, a prescaler is required to adjust for slow timing.
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
uint8_t spindle_pwm;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
} segment_t;
|
|
|
|
|
static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
|
|
|
|
|
|
|
|
|
@@ -68,17 +68,17 @@ typedef struct {
|
|
|
|
|
uint32_t counter_x, // Counter variables for the bresenham line tracer
|
|
|
|
|
counter_y,
|
|
|
|
|
counter_z;
|
|
|
|
|
#ifdef STEP_PULSE_DELAY
|
|
|
|
|
#ifdef STEP_PULSE_DELAY
|
|
|
|
|
uint8_t step_bits; // Stores out_bits output to complete the step pulse delay
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
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; // The next stepping-bits to be output
|
|
|
|
|
uint8_t dir_outbits;
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
uint32_t steps[N_AXIS];
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uint16_t step_count; // Steps remaining in line segment motion
|
|
|
|
|
uint8_t exec_block_index; // Tracks the current st_block index. Change indicates new block.
|
|
|
|
@@ -119,12 +119,12 @@ typedef struct {
|
|
|
|
|
float step_per_mm;
|
|
|
|
|
float req_mm_increment;
|
|
|
|
|
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
uint8_t last_st_block_index;
|
|
|
|
|
float last_steps_remaining;
|
|
|
|
|
float last_step_per_mm;
|
|
|
|
|
float last_dt_remainder;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uint8_t ramp_type; // Current segment ramp state
|
|
|
|
|
float mm_complete; // End of velocity profile from end of current planner block in (mm).
|
|
|
|
@@ -135,10 +135,10 @@ typedef struct {
|
|
|
|
|
float accelerate_until; // Acceleration ramp end measured from end of block (mm)
|
|
|
|
|
float decelerate_after; // Deceleration ramp start measured from end of block (mm)
|
|
|
|
|
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
|
|
|
|
|
uint8_t current_spindle_pwm;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
} st_prep_t;
|
|
|
|
|
static st_prep_t prep;
|
|
|
|
|
|
|
|
|
@@ -209,18 +209,18 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste
|
|
|
|
|
|
|
|
|
|
TIMERG0.int_clr_timers.t0 = 1;
|
|
|
|
|
|
|
|
|
|
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
|
|
|
|
|
if (busy) {
|
|
|
|
|
return; // The busy-flag is used to avoid reentering this interrupt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the direction pins a couple of nanoseconds before we step the steppers
|
|
|
|
|
set_direction_pins_on(st.dir_outbits);
|
|
|
|
|
// TO DO ... do we need a direction change delay?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef USE_RMT_STEPS
|
|
|
|
|
stepperRMT_Outputs();
|
|
|
|
|
#else
|
|
|
|
|
set_stepper_pins_on(st.step_outbits);
|
|
|
|
|
step_pulse_off_time = esp_timer_get_time() + (settings.pulse_microseconds); // determine when to turn off pulse
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
busy = true;
|
|
|
|
|
// If there is no step segment, attempt to pop one from the stepper buffer
|
|
|
|
@@ -245,25 +245,27 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste
|
|
|
|
|
}
|
|
|
|
|
st.dir_outbits = st.exec_block->direction_bits ^ settings.dir_invert_mask;
|
|
|
|
|
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
#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;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
// Set real-time spindle output as segment is loaded, just prior to the first step.
|
|
|
|
|
spindle_set_speed(st.exec_segment->spindle_pwm);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// Segment buffer empty. Shutdown.
|
|
|
|
|
st_go_idle();
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
// Ensure pwm is set properly upon completion of rate-controlled motion.
|
|
|
|
|
if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
|
|
|
|
|
#endif
|
|
|
|
|
if (st.exec_block->is_pwm_rate_adjusted) {
|
|
|
|
|
spindle_set_speed(SPINDLE_PWM_OFF_VALUE);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end
|
|
|
|
|
return; // Nothing to do but exit.
|
|
|
|
|
}
|
|
|
|
@@ -271,65 +273,80 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check probing state.
|
|
|
|
|
if (sys_probe_state == PROBE_ACTIVE) { probe_state_monitor(); }
|
|
|
|
|
if (sys_probe_state == PROBE_ACTIVE) {
|
|
|
|
|
probe_state_monitor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset step out bits.
|
|
|
|
|
st.step_outbits = 0;
|
|
|
|
|
|
|
|
|
|
// Execute step displacement profile by Bresenham line algorithm
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
st.counter_x += st.steps[X_AXIS];
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
st.counter_x += st.exec_block->steps[X_AXIS];
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
if (st.counter_x > st.exec_block->step_event_count) {
|
|
|
|
|
st.step_outbits |= (1<<X_STEP_BIT);
|
|
|
|
|
st.counter_x -= st.exec_block->step_event_count;
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<X_DIRECTION_BIT)) { sys_position[X_AXIS]--; }
|
|
|
|
|
else { sys_position[X_AXIS]++; }
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<X_DIRECTION_BIT)) {
|
|
|
|
|
sys_position[X_AXIS]--;
|
|
|
|
|
} else {
|
|
|
|
|
sys_position[X_AXIS]++;
|
|
|
|
|
}
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
}
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
st.counter_y += st.steps[Y_AXIS];
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
st.counter_y += st.exec_block->steps[Y_AXIS];
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
if (st.counter_y > st.exec_block->step_event_count) {
|
|
|
|
|
st.step_outbits |= (1<<Y_STEP_BIT);
|
|
|
|
|
st.counter_y -= st.exec_block->step_event_count;
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) { sys_position[Y_AXIS]--; }
|
|
|
|
|
else { sys_position[Y_AXIS]++; }
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) {
|
|
|
|
|
sys_position[Y_AXIS]--;
|
|
|
|
|
} else {
|
|
|
|
|
sys_position[Y_AXIS]++;
|
|
|
|
|
}
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
}
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
st.counter_z += st.steps[Z_AXIS];
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
st.counter_z += st.exec_block->steps[Z_AXIS];
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
if (st.counter_z > st.exec_block->step_event_count) {
|
|
|
|
|
st.step_outbits |= (1<<Z_STEP_BIT);
|
|
|
|
|
st.counter_z -= st.exec_block->step_event_count;
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<Z_DIRECTION_BIT)) { sys_position[Z_AXIS]--; }
|
|
|
|
|
else { sys_position[Z_AXIS]++; }
|
|
|
|
|
if (st.exec_block->direction_bits & (1<<Z_DIRECTION_BIT)) {
|
|
|
|
|
sys_position[Z_AXIS]--;
|
|
|
|
|
} else {
|
|
|
|
|
sys_position[Z_AXIS]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// During a homing cycle, lock out and prevent desired axes from moving.
|
|
|
|
|
if (sys.state == STATE_HOMING) { st.step_outbits &= sys.homing_axis_lock; }
|
|
|
|
|
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.
|
|
|
|
|
st.exec_segment = NULL;
|
|
|
|
|
if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
|
|
|
|
|
if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) {
|
|
|
|
|
segment_buffer_tail = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef USE_RMT_STEPS
|
|
|
|
|
st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// wait for step pulse time to complete...some of it should have expired during code above
|
|
|
|
|
while (esp_timer_get_time() < step_pulse_off_time)
|
|
|
|
|
{
|
|
|
|
|
while (esp_timer_get_time() < step_pulse_off_time) {
|
|
|
|
|
NOP(); // spin here until time to turn off step
|
|
|
|
|
}
|
|
|
|
|
set_stepper_pins_on(0); // turn all off
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TIMERG0.hw_timer[STEP_TIMER_INDEX].config.alarm_en = TIMER_ALARM_EN;
|
|
|
|
|
|
|
|
|
@@ -340,17 +357,11 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste
|
|
|
|
|
void stepper_init()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// make the direction pins outputs
|
|
|
|
|
#ifdef X_DIRECTION_PIN
|
|
|
|
|
pinMode(X_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Y_DIRECTION_PIN
|
|
|
|
|
pinMode(Y_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Z_DIRECTION_PIN
|
|
|
|
|
pinMode(Z_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef USE_RMT_STEPS
|
|
|
|
|
grbl_send(CLIENT_SERIAL, "[MSG:Using RMT Steps}\r\n");
|
|
|
|
|
initRMT();
|
|
|
|
|
#else
|
|
|
|
|
grbl_send(CLIENT_SERIAL, "[MSG:Using Timed Steps}\r\n");
|
|
|
|
|
// make the step pins outputs
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
pinMode(X_STEP_PIN, OUTPUT);
|
|
|
|
@@ -372,6 +383,20 @@ void stepper_init()
|
|
|
|
|
#ifdef Z_STEP_B_PIN
|
|
|
|
|
pinMode(Z_STEP_B_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// make the direction pins outputs
|
|
|
|
|
#ifdef X_DIRECTION_PIN
|
|
|
|
|
pinMode(X_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Y_DIRECTION_PIN
|
|
|
|
|
pinMode(Y_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Z_DIRECTION_PIN
|
|
|
|
|
pinMode(Z_DIRECTION_PIN, OUTPUT);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// make the stepper disable pin an output
|
|
|
|
|
#ifdef STEPPERS_DISABLE_PIN
|
|
|
|
@@ -379,7 +404,7 @@ void stepper_init()
|
|
|
|
|
set_stepper_disable(true);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// setup stepper timer interrupt
|
|
|
|
|
// setup stepper timer interrupt
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
stepperDriverTimer = timerBegin( 0, // timer number
|
|
|
|
@@ -404,15 +429,99 @@ void stepper_init()
|
|
|
|
|
timer_isr_register(STEP_TIMER_GROUP, STEP_TIMER_INDEX, onStepperDriverTimer, NULL, 0, NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initRMT()
|
|
|
|
|
{
|
|
|
|
|
rmt_item32_t rmtItem[2];
|
|
|
|
|
|
|
|
|
|
rmt_config_t rmtConfig;
|
|
|
|
|
rmtConfig.rmt_mode = RMT_MODE_TX;
|
|
|
|
|
rmtConfig.clk_div = 20;
|
|
|
|
|
rmtConfig.mem_block_num = 2;
|
|
|
|
|
rmtConfig.tx_config.loop_en = false;
|
|
|
|
|
rmtConfig.tx_config.carrier_en = false;
|
|
|
|
|
rmtConfig.tx_config.carrier_freq_hz = 0;
|
|
|
|
|
rmtConfig.tx_config.carrier_duty_percent = 50;
|
|
|
|
|
rmtConfig.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
|
|
|
|
|
rmtConfig.tx_config.idle_output_en = true;
|
|
|
|
|
|
|
|
|
|
#ifdef STEP_PULSE_DELAY
|
|
|
|
|
rmtItem[0].duration0 = STEP_PULSE_DELAY * 4;
|
|
|
|
|
#else
|
|
|
|
|
rmtItem[0].duration0 = 1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
rmtItem[0].duration1 = 4 * settings.pulse_microseconds;
|
|
|
|
|
rmtItem[1].duration0 = 0;
|
|
|
|
|
rmtItem[1].duration1 = 0;
|
|
|
|
|
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
rmt_set_source_clk( (rmt_channel_t)X_RMT_CHANNEL, RMT_BASECLK_APB);
|
|
|
|
|
rmtConfig.channel = (rmt_channel_t)X_RMT_CHANNEL;
|
|
|
|
|
rmtConfig.tx_config.idle_level = bit_istrue(settings.step_invert_mask, X_AXIS) ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
|
|
|
|
rmtConfig.gpio_num = X_STEP_PIN;
|
|
|
|
|
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmt_config(&rmtConfig);
|
|
|
|
|
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef X_STEP_B_PIN
|
|
|
|
|
rmt_set_source_clk( (rmt_channel_t)X_B_RMT_CHANNEL, RMT_BASECLK_APB);
|
|
|
|
|
rmtConfig.channel = (rmt_channel_t)X_B_RMT_CHANNEL;
|
|
|
|
|
rmtConfig.tx_config.idle_level = bit_istrue(settings.step_invert_mask, X_AXIS) ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
|
|
|
|
rmtConfig.gpio_num = X_STEP_B_PIN;
|
|
|
|
|
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmt_config(&rmtConfig);
|
|
|
|
|
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
rmt_set_source_clk( (rmt_channel_t)Y_RMT_CHANNEL, RMT_BASECLK_APB);
|
|
|
|
|
rmtConfig.channel = (rmt_channel_t)Y_RMT_CHANNEL;
|
|
|
|
|
rmtConfig.tx_config.idle_level = bit_istrue(settings.step_invert_mask, Y_AXIS) ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
|
|
|
|
rmtConfig.gpio_num = Y_STEP_PIN;
|
|
|
|
|
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmt_config(&rmtConfig);
|
|
|
|
|
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Y_STEP_B_PIN
|
|
|
|
|
rmt_set_source_clk( (rmt_channel_t)Y_B_RMT_CHANNEL, RMT_BASECLK_APB);
|
|
|
|
|
rmtConfig.channel = (rmt_channel_t)Y_B_RMT_CHANNEL;
|
|
|
|
|
rmtConfig.tx_config.idle_level = bit_istrue(settings.step_invert_mask, Y_AXIS) ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
|
|
|
|
rmtConfig.gpio_num = Y_STEP_B_PIN;
|
|
|
|
|
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmt_config(&rmtConfig);
|
|
|
|
|
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
rmt_set_source_clk( (rmt_channel_t)Z_RMT_CHANNEL, RMT_BASECLK_APB);
|
|
|
|
|
rmtConfig.channel = (rmt_channel_t)Z_RMT_CHANNEL;
|
|
|
|
|
rmtConfig.tx_config.idle_level = bit_istrue(settings.step_invert_mask, Z_AXIS) ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW;
|
|
|
|
|
rmtConfig.gpio_num = Z_STEP_PIN;
|
|
|
|
|
rmtItem[0].level0 = rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmtItem[0].level1 = !rmtConfig.tx_config.idle_level;
|
|
|
|
|
rmt_config(&rmtConfig);
|
|
|
|
|
rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// enabled. Startup init and limits call this function but shouldn't start the cycle.
|
|
|
|
|
void st_wake_up()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
//Serial.println("st_wake_up()");
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Enable stepper drivers.
|
|
|
|
|
set_stepper_disable(false);
|
|
|
|
@@ -425,12 +534,12 @@ void st_wake_up()
|
|
|
|
|
st.step_outbits = step_port_invert_mask;
|
|
|
|
|
|
|
|
|
|
// Initialize step pulse timing from settings. Here to ensure updating after re-writing.
|
|
|
|
|
#ifdef STEP_PULSE_DELAY
|
|
|
|
|
#ifdef STEP_PULSE_DELAY
|
|
|
|
|
// Step pulse delay handling is not require with ESP32...the RMT function does it.
|
|
|
|
|
#else // Normal operation
|
|
|
|
|
#else // Normal operation
|
|
|
|
|
// Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
|
|
|
|
|
st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Enable Stepper Driver Interrupt
|
|
|
|
|
Stepper_Timer_Start();
|
|
|
|
@@ -440,9 +549,9 @@ void st_wake_up()
|
|
|
|
|
void st_reset()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
//Serial.println("st_reset()");
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
// Initialize stepper driver idle state.
|
|
|
|
|
st_go_idle();
|
|
|
|
|
|
|
|
|
@@ -470,74 +579,125 @@ void st_reset()
|
|
|
|
|
void set_direction_pins_on(uint8_t onMask)
|
|
|
|
|
{
|
|
|
|
|
// inverts are applied in step generation
|
|
|
|
|
#ifdef X_DIRECTION_PIN
|
|
|
|
|
#ifdef X_DIRECTION_PIN
|
|
|
|
|
digitalWrite(X_DIRECTION_PIN, (onMask & (1<<X_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Y_DIRECTION_PIN
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Y_DIRECTION_PIN
|
|
|
|
|
digitalWrite(Y_DIRECTION_PIN, (onMask & (1<<Y_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Z_DIRECTION_PIN
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Z_DIRECTION_PIN
|
|
|
|
|
digitalWrite(Z_DIRECTION_PIN, (onMask & (1<<Z_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef USE_GANGED_AXES
|
|
|
|
|
// basic one motor per axis
|
|
|
|
|
void set_stepper_pins_on(uint8_t onMask)
|
|
|
|
|
// basic one motor per axis
|
|
|
|
|
void set_stepper_pins_on(uint8_t onMask)
|
|
|
|
|
{
|
|
|
|
|
onMask ^= settings.step_invert_mask; // invert pins as required by invert mask
|
|
|
|
|
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
digitalWrite(X_STEP_PIN, (onMask & (1<<X_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
digitalWrite(Y_STEP_PIN, (onMask & (1<<Y_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
digitalWrite(Z_STEP_PIN, (onMask & (1<<Z_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#else // we use ganged axes
|
|
|
|
|
void set_stepper_pins_on(uint8_t onMask)
|
|
|
|
|
void set_stepper_pins_on(uint8_t onMask)
|
|
|
|
|
{
|
|
|
|
|
onMask ^= settings.step_invert_mask; // invert pins as required by invert mask
|
|
|
|
|
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
#ifndef X_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
#ifndef X_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
digitalWrite(X_STEP_PIN, (onMask & (1<<X_AXIS)));
|
|
|
|
|
#else // is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) )
|
|
|
|
|
#else // is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) ) {
|
|
|
|
|
digitalWrite(X_STEP_PIN, (onMask & (1<<X_AXIS)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) )
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) ) {
|
|
|
|
|
digitalWrite(X_STEP_B_PIN, (onMask & (1<<X_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
#ifndef Y_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
#ifndef Y_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
digitalWrite(Y_STEP_PIN, (onMask & (1<<Y_AXIS)));
|
|
|
|
|
#else // is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) )
|
|
|
|
|
#else // is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) ) {
|
|
|
|
|
digitalWrite(Y_STEP_PIN, (onMask & (1<<Y_AXIS)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) )
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) ) {
|
|
|
|
|
digitalWrite(Y_STEP_B_PIN, (onMask & (1<<Y_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ganged z not supported yet
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
digitalWrite(Z_STEP_PIN, (onMask & (1<<Z_AXIS)));
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set stepper pulse output pins
|
|
|
|
|
inline IRAM_ATTR static void stepperRMT_Outputs()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#ifdef X_STEP_PIN
|
|
|
|
|
if(st.step_outbits & (1<<X_AXIS)) {
|
|
|
|
|
#ifndef X_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
RMT.conf_ch[X_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[X_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
#else // it is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) ) {
|
|
|
|
|
RMT.conf_ch[X_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[X_RMT_CHANNEL].conf1.tx_start = 1; }
|
|
|
|
|
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) ) {
|
|
|
|
|
RMT.conf_ch[X_B_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[X_B_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Y_STEP_PIN
|
|
|
|
|
if(st.step_outbits & (1<<Y_AXIS)) {
|
|
|
|
|
#ifndef Y_STEP_B_PIN // if not a ganged axis
|
|
|
|
|
RMT.conf_ch[Y_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[Y_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
#else // it is a ganged axis
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_A) ) {
|
|
|
|
|
RMT.conf_ch[Y_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[Y_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
}
|
|
|
|
|
if ( (ganged_mode == SQUARING_MODE_DUAL) || (ganged_mode == SQUARING_MODE_B) ) {
|
|
|
|
|
RMT.conf_ch[Y_B_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[Y_B_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Z_STEP_PIN
|
|
|
|
|
if(st.step_outbits & (1<<Z_AXIS)) {
|
|
|
|
|
RMT.conf_ch[Z_RMT_CHANNEL].conf1.mem_rd_rst = 1;
|
|
|
|
|
RMT.conf_ch[Z_RMT_CHANNEL].conf1.tx_start = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stepper shutdown
|
|
|
|
|
void st_go_idle()
|
|
|
|
@@ -560,16 +720,14 @@ void st_go_idle()
|
|
|
|
|
|
|
|
|
|
//vTaskDelay(settings.stepper_idle_lock_time / portTICK_PERIOD_MS); // this probably does not work when called from ISR
|
|
|
|
|
//pin_state = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
} else {
|
|
|
|
|
set_stepper_disable(pin_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_stepper_pins_on(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called by planner_recalculate() when the executing block is updated by the new plan.
|
|
|
|
|
// Called by planner_recalculate() when the executing block is updated by the new plan.
|
|
|
|
|
void st_update_plan_block_parameters()
|
|
|
|
|
{
|
|
|
|
|
if (pl_block != NULL) { // Ignore if at start of a new block.
|
|
|
|
@@ -580,9 +738,9 @@ void st_update_plan_block_parameters()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
// Changes the run state of the step segment buffer to execute the special parking motion.
|
|
|
|
|
void st_parking_setup_buffer()
|
|
|
|
|
{
|
|
|
|
|
// Changes the run state of the step segment buffer to execute the special parking motion.
|
|
|
|
|
void st_parking_setup_buffer()
|
|
|
|
|
{
|
|
|
|
|
// Store step execution data of partially completed block, if necessary.
|
|
|
|
|
if (prep.recalculate_flag & PREP_FLAG_HOLD_PARTIAL_BLOCK) {
|
|
|
|
|
prep.last_st_block_index = prep.st_block_index;
|
|
|
|
@@ -594,12 +752,12 @@ void st_update_plan_block_parameters()
|
|
|
|
|
prep.recalculate_flag |= PREP_FLAG_PARKING;
|
|
|
|
|
prep.recalculate_flag &= ~(PREP_FLAG_RECALCULATE);
|
|
|
|
|
pl_block = NULL; // Always reset parking motion to reload new block.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restores the step segment buffer to the normal run state after a parking motion.
|
|
|
|
|
void st_parking_restore_buffer()
|
|
|
|
|
{
|
|
|
|
|
// Restores the step segment buffer to the normal run state after a parking motion.
|
|
|
|
|
void st_parking_restore_buffer()
|
|
|
|
|
{
|
|
|
|
|
// Restore step execution data and flags of partially completed block, if necessary.
|
|
|
|
|
if (prep.recalculate_flag & PREP_FLAG_HOLD_PARTIAL_BLOCK) {
|
|
|
|
|
st_prep_block = &st_block_buffer[prep.last_st_block_index];
|
|
|
|
@@ -613,7 +771,7 @@ void st_update_plan_block_parameters()
|
|
|
|
|
prep.recalculate_flag = false;
|
|
|
|
|
}
|
|
|
|
|
pl_block = NULL; // Set to reload next block.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Generates the step and direction port invert masks used in the Stepper Interrupt Driver.
|
|
|
|
@@ -637,7 +795,9 @@ void st_generate_step_dir_invert_masks()
|
|
|
|
|
static uint8_t st_next_block_index(uint8_t block_index)
|
|
|
|
|
{
|
|
|
|
|
block_index++;
|
|
|
|
|
if ( block_index == (SEGMENT_BUFFER_SIZE-1) ) { return(0); }
|
|
|
|
|
if ( block_index == (SEGMENT_BUFFER_SIZE-1) ) {
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
return(block_index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -657,7 +817,9 @@ static uint8_t st_next_block_index(uint8_t block_index)
|
|
|
|
|
void st_prep_buffer()
|
|
|
|
|
{
|
|
|
|
|
// Block step prep buffer, while in a suspend state and there is no suspend motion to execute.
|
|
|
|
|
if (bit_istrue(sys.step_control,STEP_CONTROL_END_MOTION)) { return; }
|
|
|
|
|
if (bit_istrue(sys.step_control,STEP_CONTROL_END_MOTION)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (segment_buffer_tail != segment_next_head) { // Check if we need to fill the buffer.
|
|
|
|
|
|
|
|
|
@@ -665,19 +827,27 @@ void st_prep_buffer()
|
|
|
|
|
if (pl_block == NULL) {
|
|
|
|
|
|
|
|
|
|
// Query planner for a queued block
|
|
|
|
|
if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) { pl_block = plan_get_system_motion_block(); }
|
|
|
|
|
else { pl_block = plan_get_current_block(); }
|
|
|
|
|
if (pl_block == NULL) { return; } // No planner blocks. Exit.
|
|
|
|
|
if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
|
|
|
|
|
pl_block = plan_get_system_motion_block();
|
|
|
|
|
} else {
|
|
|
|
|
pl_block = plan_get_current_block();
|
|
|
|
|
}
|
|
|
|
|
if (pl_block == NULL) {
|
|
|
|
|
return; // No planner blocks. Exit.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if we need to only recompute the velocity profile or load a new block.
|
|
|
|
|
if (prep.recalculate_flag & PREP_FLAG_RECALCULATE) {
|
|
|
|
|
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (prep.recalculate_flag & PREP_FLAG_PARKING) { prep.recalculate_flag &= ~(PREP_FLAG_RECALCULATE); }
|
|
|
|
|
else { prep.recalculate_flag = false; }
|
|
|
|
|
#else
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (prep.recalculate_flag & PREP_FLAG_PARKING) {
|
|
|
|
|
prep.recalculate_flag &= ~(PREP_FLAG_RECALCULATE);
|
|
|
|
|
} else {
|
|
|
|
|
prep.recalculate_flag = false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
prep.recalculate_flag = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
@@ -690,16 +860,20 @@ void st_prep_buffer()
|
|
|
|
|
st_prep_block = &st_block_buffer[prep.st_block_index];
|
|
|
|
|
st_prep_block->direction_bits = pl_block->direction_bits;
|
|
|
|
|
uint8_t idx;
|
|
|
|
|
#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx]; }
|
|
|
|
|
#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
for (idx=0; idx<N_AXIS; idx++) {
|
|
|
|
|
st_prep_block->steps[idx] = pl_block->steps[idx];
|
|
|
|
|
}
|
|
|
|
|
st_prep_block->step_event_count = pl_block->step_event_count;
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
// With AMASS enabled, simply bit-shift multiply all Bresenham data by the max AMASS
|
|
|
|
|
// level, such that we never divide beyond the original data anywhere in the algorithm.
|
|
|
|
|
// If the original data is divided, we can lose a step from integer roundoff.
|
|
|
|
|
for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx] << MAX_AMASS_LEVEL; }
|
|
|
|
|
for (idx=0; idx<N_AXIS; idx++) {
|
|
|
|
|
st_prep_block->steps[idx] = pl_block->steps[idx] << MAX_AMASS_LEVEL;
|
|
|
|
|
}
|
|
|
|
|
st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Initialize segment buffer data for generating the segments.
|
|
|
|
|
prep.steps_remaining = (float)pl_block->step_event_count;
|
|
|
|
@@ -716,7 +890,7 @@ void st_prep_buffer()
|
|
|
|
|
prep.current_speed = sqrt(pl_block->entry_speed_sqr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
// Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
|
|
|
|
|
// spindle off.
|
|
|
|
|
st_prep_block->is_pwm_rate_adjusted = false;
|
|
|
|
@@ -727,7 +901,7 @@ void st_prep_buffer()
|
|
|
|
|
st_prep_block->is_pwm_rate_adjusted = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------
|
|
|
|
@@ -821,9 +995,9 @@ void st_prep_buffer()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); // Force update whenever updating block.
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize new segment
|
|
|
|
@@ -853,7 +1027,9 @@ void st_prep_buffer()
|
|
|
|
|
float speed_var; // Speed worker variable
|
|
|
|
|
float mm_remaining = pl_block->millimeters; // New segment distance from end of block.
|
|
|
|
|
float minimum_mm = mm_remaining-prep.req_mm_increment; // Guarantee at least one step.
|
|
|
|
|
if (minimum_mm < 0.0) { minimum_mm = 0.0; }
|
|
|
|
|
if (minimum_mm < 0.0) {
|
|
|
|
|
minimum_mm = 0.0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
switch (prep.ramp_type) {
|
|
|
|
@@ -879,8 +1055,11 @@ void st_prep_buffer()
|
|
|
|
|
// Acceleration-cruise, acceleration-deceleration ramp junction, or end of block.
|
|
|
|
|
mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB
|
|
|
|
|
time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
|
|
|
|
|
if (mm_remaining == prep.decelerate_after) { prep.ramp_type = RAMP_DECEL; }
|
|
|
|
|
else { prep.ramp_type = RAMP_CRUISE; }
|
|
|
|
|
if (mm_remaining == prep.decelerate_after) {
|
|
|
|
|
prep.ramp_type = RAMP_DECEL;
|
|
|
|
|
} else {
|
|
|
|
|
prep.ramp_type = RAMP_CRUISE;
|
|
|
|
|
}
|
|
|
|
|
prep.current_speed = prep.maximum_speed;
|
|
|
|
|
} else { // Acceleration only.
|
|
|
|
|
prep.current_speed += speed_var;
|
|
|
|
@@ -918,8 +1097,9 @@ void st_prep_buffer()
|
|
|
|
|
prep.current_speed = prep.exit_speed;
|
|
|
|
|
}
|
|
|
|
|
dt += time_var; // Add computed ramp time to total segment time.
|
|
|
|
|
if (dt < dt_max) { time_var = dt_max - dt; } // **Incomplete** At ramp junction.
|
|
|
|
|
else {
|
|
|
|
|
if (dt < dt_max) {
|
|
|
|
|
time_var = dt_max - dt; // **Incomplete** At ramp junction.
|
|
|
|
|
} else {
|
|
|
|
|
if (mm_remaining > minimum_mm) { // Check for very slow segments with zero steps.
|
|
|
|
|
// Increase segment time to ensure at least one step in segment. Override and loop
|
|
|
|
|
// through distance calculations until minimum_mm or mm_complete.
|
|
|
|
@@ -931,7 +1111,7 @@ void st_prep_buffer()
|
|
|
|
|
}
|
|
|
|
|
} while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete.
|
|
|
|
|
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
#ifdef VARIABLE_SPINDLE
|
|
|
|
|
/* -----------------------------------------------------------------------------------
|
|
|
|
|
Compute spindle speed PWM output for step segment
|
|
|
|
|
*/
|
|
|
|
@@ -940,7 +1120,9 @@ void st_prep_buffer()
|
|
|
|
|
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.
|
|
|
|
|
if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_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);
|
|
|
|
@@ -952,7 +1134,7 @@ void st_prep_buffer()
|
|
|
|
|
}
|
|
|
|
|
prep_segment->spindle_pwm = prep.current_spindle_pwm; // Reload segment PWM value
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------------------------
|
|
|
|
|
Compute segment step rate, steps to execute, and apply necessary rate corrections.
|
|
|
|
@@ -975,9 +1157,11 @@ void st_prep_buffer()
|
|
|
|
|
// Less than one step to decelerate to zero speed, but already very close. AMASS
|
|
|
|
|
// requires full steps to execute. So, just bail.
|
|
|
|
|
bit_true(sys.step_control,STEP_CONTROL_END_MOTION);
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) { prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK; }
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) {
|
|
|
|
|
prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return; // Segment not generated, but current step data still retained.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -996,20 +1180,28 @@ void st_prep_buffer()
|
|
|
|
|
// Compute CPU cycles per step for the prepped segment.
|
|
|
|
|
uint32_t cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (cycles/step)
|
|
|
|
|
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
|
|
|
|
// Compute step timing and multi-axis smoothing level.
|
|
|
|
|
// NOTE: AMASS overdrives the timer with each level, so only one prescalar is required.
|
|
|
|
|
if (cycles < AMASS_LEVEL1) { prep_segment->amass_level = 0; }
|
|
|
|
|
else {
|
|
|
|
|
if (cycles < AMASS_LEVEL2) { prep_segment->amass_level = 1; }
|
|
|
|
|
else if (cycles < AMASS_LEVEL3) { prep_segment->amass_level = 2; }
|
|
|
|
|
else { prep_segment->amass_level = 3; }
|
|
|
|
|
if (cycles < AMASS_LEVEL1) {
|
|
|
|
|
prep_segment->amass_level = 0;
|
|
|
|
|
} else {
|
|
|
|
|
if (cycles < AMASS_LEVEL2) {
|
|
|
|
|
prep_segment->amass_level = 1;
|
|
|
|
|
} else if (cycles < AMASS_LEVEL3) {
|
|
|
|
|
prep_segment->amass_level = 2;
|
|
|
|
|
} else {
|
|
|
|
|
prep_segment->amass_level = 3;
|
|
|
|
|
}
|
|
|
|
|
cycles >>= prep_segment->amass_level;
|
|
|
|
|
prep_segment->n_step <<= prep_segment->amass_level;
|
|
|
|
|
}
|
|
|
|
|
if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; } // < 65536 (4.1ms @ 16MHz)
|
|
|
|
|
else { prep_segment->cycles_per_tick = 0xffff; } // Just set the slowest speed possible.
|
|
|
|
|
#else
|
|
|
|
|
if (cycles < (1UL << 16)) {
|
|
|
|
|
prep_segment->cycles_per_tick = cycles; // < 65536 (4.1ms @ 16MHz)
|
|
|
|
|
} else {
|
|
|
|
|
prep_segment->cycles_per_tick = 0xffff; // Just set the slowest speed possible.
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// Compute step timing and timer prescalar for normal step generation.
|
|
|
|
|
if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz)
|
|
|
|
|
prep_segment->prescaler = 1; // prescaler: 0
|
|
|
|
@@ -1025,11 +1217,13 @@ void st_prep_buffer()
|
|
|
|
|
prep_segment->cycles_per_tick = 0xffff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Segment complete! Increment segment buffer indices, so stepper ISR can immediately execute it.
|
|
|
|
|
segment_buffer_head = segment_next_head;
|
|
|
|
|
if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; }
|
|
|
|
|
if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) {
|
|
|
|
|
segment_next_head = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update the appropriate planner and segment data.
|
|
|
|
|
pl_block->millimeters = mm_remaining;
|
|
|
|
@@ -1044,9 +1238,11 @@ void st_prep_buffer()
|
|
|
|
|
// the segment queue, where realtime protocol will set new state upon receiving the
|
|
|
|
|
// cycle stop flag from the ISR. Prep_segment is blocked until then.
|
|
|
|
|
bit_true(sys.step_control,STEP_CONTROL_END_MOTION);
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) { prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK; }
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef PARKING_ENABLE
|
|
|
|
|
if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) {
|
|
|
|
|
prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return; // Bail!
|
|
|
|
|
} else { // End of planner block
|
|
|
|
|
// The planner block is complete. All steps are set to be executed in the segment buffer.
|
|
|
|
@@ -1070,7 +1266,7 @@ void st_prep_buffer()
|
|
|
|
|
// divided by the ACCELERATION TICKS PER SECOND in seconds.
|
|
|
|
|
float st_get_realtime_rate()
|
|
|
|
|
{
|
|
|
|
|
if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)){
|
|
|
|
|
if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
|
|
|
|
|
return prep.current_speed;
|
|
|
|
|
}
|
|
|
|
|
return 0.0f;
|
|
|
|
@@ -1083,9 +1279,9 @@ void IRAM_ATTR Stepper_Timer_WritePeriod(uint64_t alarm_val)
|
|
|
|
|
|
|
|
|
|
void IRAM_ATTR Stepper_Timer_Start()
|
|
|
|
|
{
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
//Serial.println("ST Start");
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
timer_set_counter_value(STEP_TIMER_GROUP, STEP_TIMER_INDEX, 0x00000000ULL);
|
|
|
|
|
|
|
|
|
@@ -1096,9 +1292,9 @@ void IRAM_ATTR Stepper_Timer_Start()
|
|
|
|
|
|
|
|
|
|
void IRAM_ATTR Stepper_Timer_Stop()
|
|
|
|
|
{
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
#ifdef ESP_DEBUG
|
|
|
|
|
//Serial.println("ST Stop");
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
timer_pause(STEP_TIMER_GROUP, STEP_TIMER_INDEX);
|
|
|
|
|
|
|
|
|
@@ -1107,21 +1303,24 @@ void IRAM_ATTR Stepper_Timer_Stop()
|
|
|
|
|
|
|
|
|
|
void set_stepper_disable(uint8_t isOn) // isOn = true // to disable
|
|
|
|
|
{
|
|
|
|
|
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { isOn = !isOn; } // Apply pin invert.
|
|
|
|
|
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
|
|
|
|
|
isOn = !isOn; // Apply pin invert.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef STEPPERS_DISABLE_PIN
|
|
|
|
|
#ifdef STEPPERS_DISABLE_PIN
|
|
|
|
|
digitalWrite(STEPPERS_DISABLE_PIN, isOn );
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool get_stepper_disable() { // returns true if steppers are disabled
|
|
|
|
|
bool get_stepper_disable() // returns true if steppers are disabled
|
|
|
|
|
{
|
|
|
|
|
bool disabled = false;
|
|
|
|
|
|
|
|
|
|
#ifdef STEPPERS_DISABLE_PIN
|
|
|
|
|
#ifdef STEPPERS_DISABLE_PIN
|
|
|
|
|
disabled = digitalRead(STEPPERS_DISABLE_PIN);
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
return false; // thery are never disabled if there is no pin defined
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) {
|
|
|
|
|
disabled = !disabled; // Apply pin invert.
|
|
|
|
|