Luigi Santivetti | 69972f9 | 2019-11-12 22:55:40 +0000 | [diff] [blame^] | 1 | /* |
| 2 | stepper.c - stepper motor driver: executes motion plans using stepper motors |
| 3 | Part of Grbl |
| 4 | |
| 5 | Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC |
| 6 | Copyright (c) 2009-2011 Simen Svale Skogsrud |
| 7 | |
| 8 | Grbl is free software: you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation, either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 12 | |
| 13 | Grbl is distributed in the hope that it will be useful, |
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | GNU General Public License for more details. |
| 17 | |
| 18 | You should have received a copy of the GNU General Public License |
| 19 | along with Grbl. If not, see <http://www.gnu.org/licenses/>. |
| 20 | */ |
| 21 | |
| 22 | #include "grbl.h" |
| 23 | |
| 24 | |
| 25 | // Some useful constants. |
| 26 | #define DT_SEGMENT (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0)) // min/segment |
| 27 | #define REQ_MM_INCREMENT_SCALAR 1.25 |
| 28 | #define RAMP_ACCEL 0 |
| 29 | #define RAMP_CRUISE 1 |
| 30 | #define RAMP_DECEL 2 |
| 31 | #define RAMP_DECEL_OVERRIDE 3 |
| 32 | |
| 33 | #define PREP_FLAG_RECALCULATE bit(0) |
| 34 | #define PREP_FLAG_HOLD_PARTIAL_BLOCK bit(1) |
| 35 | #define PREP_FLAG_PARKING bit(2) |
| 36 | #define PREP_FLAG_DECEL_OVERRIDE bit(3) |
| 37 | |
| 38 | // Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level |
| 39 | // frequency bin starts at 0Hz and ends at its cutoff frequency. The next lower level frequency bin |
| 40 | // starts at the next higher cutoff frequency, and so on. The cutoff frequencies for each level must |
| 41 | // be considered carefully against how much it over-drives the stepper ISR, the accuracy of the 16-bit |
| 42 | // timer, and the CPU overhead. Level 0 (no AMASS, normal operation) frequency bin starts at the |
| 43 | // Level 1 cutoff frequency and up to as fast as the CPU allows (over 30kHz in limited testing). |
| 44 | // NOTE: AMASS cutoff frequency multiplied by ISR overdrive factor must not exceed maximum step frequency. |
| 45 | // NOTE: Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead |
| 46 | // and timer accuracy. Do not alter these settings unless you know what you are doing. |
| 47 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 48 | #define MAX_AMASS_LEVEL 3 |
| 49 | // AMASS_LEVEL0: Normal operation. No AMASS. No upper cutoff frequency. Starts at LEVEL1 cutoff frequency. |
| 50 | #define AMASS_LEVEL1 (F_CPU/8000) // Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz) |
| 51 | #define AMASS_LEVEL2 (F_CPU/4000) // Over-drives ISR (x4) |
| 52 | #define AMASS_LEVEL3 (F_CPU/2000) // Over-drives ISR (x8) |
| 53 | |
| 54 | #if MAX_AMASS_LEVEL <= 0 |
| 55 | error "AMASS must have 1 or more levels to operate correctly." |
| 56 | #endif |
| 57 | #endif |
| 58 | |
| 59 | |
| 60 | // Stores the planner block Bresenham algorithm execution data for the segments in the segment |
| 61 | // buffer. Normally, this buffer is partially in-use, but, for the worst case scenario, it will |
| 62 | // never exceed the number of accessible stepper buffer segments (SEGMENT_BUFFER_SIZE-1). |
| 63 | // NOTE: This data is copied from the prepped planner blocks so that the planner blocks may be |
| 64 | // discarded when entirely consumed and completed by the segment buffer. Also, AMASS alters this |
| 65 | // data for its own use. |
| 66 | typedef struct { |
| 67 | uint32_t steps[N_AXIS]; |
| 68 | uint32_t step_event_count; |
| 69 | uint8_t direction_bits; |
| 70 | #ifdef ENABLE_DUAL_AXIS |
| 71 | uint8_t direction_bits_dual; |
| 72 | #endif |
| 73 | #ifdef VARIABLE_SPINDLE |
| 74 | uint8_t is_pwm_rate_adjusted; // Tracks motions that require constant laser power/rate |
| 75 | #endif |
| 76 | } st_block_t; |
| 77 | static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1]; |
| 78 | |
| 79 | // Primary stepper segment ring buffer. Contains small, short line segments for the stepper |
| 80 | // algorithm to execute, which are "checked-out" incrementally from the first block in the |
| 81 | // planner buffer. Once "checked-out", the steps in the segments buffer cannot be modified by |
| 82 | // the planner, where the remaining planner block steps still can. |
| 83 | typedef struct { |
| 84 | uint16_t n_step; // Number of step events to be executed for this segment |
| 85 | uint16_t cycles_per_tick; // Step distance traveled per ISR tick, aka step rate. |
| 86 | uint8_t st_block_index; // Stepper block data index. Uses this information to execute this segment. |
| 87 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 88 | uint8_t amass_level; // Indicates AMASS level for the ISR to execute this segment |
| 89 | #else |
| 90 | uint8_t prescaler; // Without AMASS, a prescaler is required to adjust for slow timing. |
| 91 | #endif |
| 92 | #ifdef VARIABLE_SPINDLE |
| 93 | uint8_t spindle_pwm; |
| 94 | #endif |
| 95 | } segment_t; |
| 96 | static segment_t segment_buffer[SEGMENT_BUFFER_SIZE]; |
| 97 | |
| 98 | // Stepper ISR data struct. Contains the running data for the main stepper ISR. |
| 99 | typedef struct { |
| 100 | // Used by the bresenham line algorithm |
| 101 | uint32_t counter_x, // Counter variables for the bresenham line tracer |
| 102 | counter_y, |
| 103 | counter_z; |
| 104 | #ifdef STEP_PULSE_DELAY |
| 105 | uint8_t step_bits; // Stores out_bits output to complete the step pulse delay |
| 106 | #endif |
| 107 | |
| 108 | uint8_t execute_step; // Flags step execution for each interrupt. |
| 109 | uint8_t step_pulse_time; // Step pulse reset time after step rise |
| 110 | uint8_t step_outbits; // The next stepping-bits to be output |
| 111 | uint8_t dir_outbits; |
| 112 | #ifdef ENABLE_DUAL_AXIS |
| 113 | uint8_t step_outbits_dual; |
| 114 | uint8_t dir_outbits_dual; |
| 115 | #endif |
| 116 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 117 | uint32_t steps[N_AXIS]; |
| 118 | #endif |
| 119 | |
| 120 | uint16_t step_count; // Steps remaining in line segment motion |
| 121 | uint8_t exec_block_index; // Tracks the current st_block index. Change indicates new block. |
| 122 | st_block_t *exec_block; // Pointer to the block data for the segment being executed |
| 123 | segment_t *exec_segment; // Pointer to the segment being executed |
| 124 | } stepper_t; |
| 125 | static stepper_t st; |
| 126 | |
| 127 | // Step segment ring buffer indices |
| 128 | static volatile uint8_t segment_buffer_tail; |
| 129 | static uint8_t segment_buffer_head; |
| 130 | static uint8_t segment_next_head; |
| 131 | |
| 132 | // Step and direction port invert masks. |
| 133 | static uint8_t step_port_invert_mask; |
| 134 | static uint8_t dir_port_invert_mask; |
| 135 | #ifdef ENABLE_DUAL_AXIS |
| 136 | static uint8_t step_port_invert_mask_dual; |
| 137 | static uint8_t dir_port_invert_mask_dual; |
| 138 | #endif |
| 139 | |
| 140 | // Used to avoid ISR nesting of the "Stepper Driver Interrupt". Should never occur though. |
| 141 | static volatile uint8_t busy; |
| 142 | |
| 143 | // Pointers for the step segment being prepped from the planner buffer. Accessed only by the |
| 144 | // main program. Pointers may be planning segments or planner blocks ahead of what being executed. |
| 145 | static plan_block_t *pl_block; // Pointer to the planner block being prepped |
| 146 | static st_block_t *st_prep_block; // Pointer to the stepper block data being prepped |
| 147 | |
| 148 | // Segment preparation data struct. Contains all the necessary information to compute new segments |
| 149 | // based on the current executing planner block. |
| 150 | typedef struct { |
| 151 | uint8_t st_block_index; // Index of stepper common data block being prepped |
| 152 | uint8_t recalculate_flag; |
| 153 | |
| 154 | float dt_remainder; |
| 155 | float steps_remaining; |
| 156 | float step_per_mm; |
| 157 | float req_mm_increment; |
| 158 | |
| 159 | #ifdef PARKING_ENABLE |
| 160 | uint8_t last_st_block_index; |
| 161 | float last_steps_remaining; |
| 162 | float last_step_per_mm; |
| 163 | float last_dt_remainder; |
| 164 | #endif |
| 165 | |
| 166 | uint8_t ramp_type; // Current segment ramp state |
| 167 | float mm_complete; // End of velocity profile from end of current planner block in (mm). |
| 168 | // NOTE: This value must coincide with a step(no mantissa) when converted. |
| 169 | float current_speed; // Current speed at the end of the segment buffer (mm/min) |
| 170 | float maximum_speed; // Maximum speed of executing block. Not always nominal speed. (mm/min) |
| 171 | float exit_speed; // Exit speed of executing block (mm/min) |
| 172 | float accelerate_until; // Acceleration ramp end measured from end of block (mm) |
| 173 | float decelerate_after; // Deceleration ramp start measured from end of block (mm) |
| 174 | |
| 175 | #ifdef VARIABLE_SPINDLE |
| 176 | float inv_rate; // Used by PWM laser mode to speed up segment calculations. |
| 177 | uint8_t current_spindle_pwm; |
| 178 | #endif |
| 179 | } st_prep_t; |
| 180 | static st_prep_t prep; |
| 181 | |
| 182 | |
| 183 | /* BLOCK VELOCITY PROFILE DEFINITION |
| 184 | __________________________ |
| 185 | /| |\ _________________ ^ |
| 186 | / | | \ /| |\ | |
| 187 | / | | \ / | | \ s |
| 188 | / | | | | | \ p |
| 189 | / | | | | | \ e |
| 190 | +-----+------------------------+---+--+---------------+----+ e |
| 191 | | BLOCK 1 ^ BLOCK 2 | d |
| 192 | | |
| 193 | time -----> EXAMPLE: Block 2 entry speed is at max junction velocity |
| 194 | |
| 195 | The planner block buffer is planned assuming constant acceleration velocity profiles and are |
| 196 | continuously joined at block junctions as shown above. However, the planner only actively computes |
| 197 | the block entry speeds for an optimal velocity plan, but does not compute the block internal |
| 198 | velocity profiles. These velocity profiles are computed ad-hoc as they are executed by the |
| 199 | stepper algorithm and consists of only 7 possible types of profiles: cruise-only, cruise- |
| 200 | deceleration, acceleration-cruise, acceleration-only, deceleration-only, full-trapezoid, and |
| 201 | triangle(no cruise). |
| 202 | |
| 203 | maximum_speed (< nominal_speed) -> + |
| 204 | +--------+ <- maximum_speed (= nominal_speed) /|\ |
| 205 | / \ / | \ |
| 206 | current_speed -> + \ / | + <- exit_speed |
| 207 | | + <- exit_speed / | | |
| 208 | +-------------+ current_speed -> +----+--+ |
| 209 | time --> ^ ^ ^ ^ |
| 210 | | | | | |
| 211 | decelerate_after(in mm) decelerate_after(in mm) |
| 212 | ^ ^ ^ ^ |
| 213 | | | | | |
| 214 | accelerate_until(in mm) accelerate_until(in mm) |
| 215 | |
| 216 | The step segment buffer computes the executing block velocity profile and tracks the critical |
| 217 | parameters for the stepper algorithm to accurately trace the profile. These critical parameters |
| 218 | are shown and defined in the above illustration. |
| 219 | */ |
| 220 | |
| 221 | |
| 222 | // Stepper state initialization. Cycle should only start if the st.cycle_start flag is |
| 223 | // enabled. Startup init and limits call this function but shouldn't start the cycle. |
| 224 | void st_wake_up() |
| 225 | { |
| 226 | // Enable stepper drivers. |
| 227 | if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); } |
| 228 | else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); } |
| 229 | |
| 230 | // Initialize stepper output bits to ensure first ISR call does not step. |
| 231 | st.step_outbits = step_port_invert_mask; |
| 232 | |
| 233 | // Initialize step pulse timing from settings. Here to ensure updating after re-writing. |
| 234 | #ifdef STEP_PULSE_DELAY |
| 235 | // Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope. |
| 236 | st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3); |
| 237 | // Set delay between direction pin write and step command. |
| 238 | OCR0A = -(((settings.pulse_microseconds)*TICKS_PER_MICROSECOND) >> 3); |
| 239 | #else // Normal operation |
| 240 | // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement. |
| 241 | st.step_pulse_time = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); |
| 242 | #endif |
| 243 | |
| 244 | // Enable Stepper Driver Interrupt |
| 245 | TIMSK1 |= (1<<OCIE1A); |
| 246 | } |
| 247 | |
| 248 | |
| 249 | // Stepper shutdown |
| 250 | void st_go_idle() |
| 251 | { |
| 252 | // Disable Stepper Driver Interrupt. Allow Stepper Port Reset Interrupt to finish, if active. |
| 253 | TIMSK1 &= ~(1<<OCIE1A); // Disable Timer1 interrupt |
| 254 | TCCR1B = (TCCR1B & ~((1<<CS12) | (1<<CS11))) | (1<<CS10); // Reset clock to no prescaling. |
| 255 | busy = false; |
| 256 | |
| 257 | // Set stepper driver idle state, disabled or enabled, depending on settings and circumstances. |
| 258 | bool pin_state = false; // Keep enabled. |
| 259 | if (((settings.stepper_idle_lock_time != 0xff) || sys_rt_exec_alarm || sys.state == STATE_SLEEP) && sys.state != STATE_HOMING) { |
| 260 | // Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete |
| 261 | // stop and not drift from residual inertial forces at the end of the last movement. |
| 262 | delay_ms(settings.stepper_idle_lock_time); |
| 263 | pin_state = true; // Override. Disable steppers. |
| 264 | } |
| 265 | if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = !pin_state; } // Apply pin invert. |
| 266 | if (pin_state) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); } |
| 267 | else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); } |
| 268 | } |
| 269 | |
| 270 | |
| 271 | /* "The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. Grbl employs |
| 272 | the venerable Bresenham line algorithm to manage and exactly synchronize multi-axis moves. |
| 273 | Unlike the popular DDA algorithm, the Bresenham algorithm is not susceptible to numerical |
| 274 | round-off errors and only requires fast integer counters, meaning low computational overhead |
| 275 | and maximizing the Arduino's capabilities. However, the downside of the Bresenham algorithm |
| 276 | is, for certain multi-axis motions, the non-dominant axes may suffer from un-smooth step |
| 277 | pulse trains, or aliasing, which can lead to strange audible noises or shaking. This is |
| 278 | particularly noticeable or may cause motion issues at low step frequencies (0-5kHz), but |
| 279 | is usually not a physical problem at higher frequencies, although audible. |
| 280 | To improve Bresenham multi-axis performance, Grbl uses what we call an Adaptive Multi-Axis |
| 281 | Step Smoothing (AMASS) algorithm, which does what the name implies. At lower step frequencies, |
| 282 | AMASS artificially increases the Bresenham resolution without effecting the algorithm's |
| 283 | innate exactness. AMASS adapts its resolution levels automatically depending on the step |
| 284 | frequency to be executed, meaning that for even lower step frequencies the step smoothing |
| 285 | level increases. Algorithmically, AMASS is acheived by a simple bit-shifting of the Bresenham |
| 286 | step count for each AMASS level. For example, for a Level 1 step smoothing, we bit shift |
| 287 | the Bresenham step event count, effectively multiplying it by 2, while the axis step counts |
| 288 | remain the same, and then double the stepper ISR frequency. In effect, we are allowing the |
| 289 | non-dominant Bresenham axes step in the intermediate ISR tick, while the dominant axis is |
| 290 | stepping every two ISR ticks, rather than every ISR tick in the traditional sense. At AMASS |
| 291 | Level 2, we simply bit-shift again, so the non-dominant Bresenham axes can step within any |
| 292 | of the four ISR ticks, the dominant axis steps every four ISR ticks, and quadruple the |
| 293 | stepper ISR frequency. And so on. This, in effect, virtually eliminates multi-axis aliasing |
| 294 | issues with the Bresenham algorithm and does not significantly alter Grbl's performance, but |
| 295 | in fact, more efficiently utilizes unused CPU cycles overall throughout all configurations. |
| 296 | AMASS retains the Bresenham algorithm exactness by requiring that it always executes a full |
| 297 | Bresenham step, regardless of AMASS Level. Meaning that for an AMASS Level 2, all four |
| 298 | intermediate steps must be completed such that baseline Bresenham (Level 0) count is always |
| 299 | retained. Similarly, AMASS Level 3 means all eight intermediate steps must be executed. |
| 300 | Although the AMASS Levels are in reality arbitrary, where the baseline Bresenham counts can |
| 301 | be multiplied by any integer value, multiplication by powers of two are simply used to ease |
| 302 | CPU overhead with bitshift integer operations. |
| 303 | This interrupt is simple and dumb by design. All the computational heavy-lifting, as in |
| 304 | determining accelerations, is performed elsewhere. This interrupt pops pre-computed segments, |
| 305 | defined as constant velocity over n number of steps, from the step segment buffer and then |
| 306 | executes them by pulsing the stepper pins appropriately via the Bresenham algorithm. This |
| 307 | ISR is supported by The Stepper Port Reset Interrupt which it uses to reset the stepper port |
| 308 | after each pulse. The bresenham line tracer algorithm controls all stepper outputs |
| 309 | simultaneously with these two interrupts. |
| 310 | |
| 311 | NOTE: This interrupt must be as efficient as possible and complete before the next ISR tick, |
| 312 | which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in |
| 313 | ISR is 5usec typical and 25usec maximum, well below requirement. |
| 314 | NOTE: This ISR expects at least one step to be executed per segment. |
| 315 | */ |
| 316 | // TODO: Replace direct updating of the int32 position counters in the ISR somehow. Perhaps use smaller |
| 317 | // int8 variables and update position counters only when a segment completes. This can get complicated |
| 318 | // with probing and homing cycles that require true real-time positions. |
| 319 | ISR(TIMER1_COMPA_vect) |
| 320 | { |
| 321 | if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt |
| 322 | |
| 323 | // Set the direction pins a couple of nanoseconds before we step the steppers |
| 324 | DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK); |
| 325 | #ifdef ENABLE_DUAL_AXIS |
| 326 | DIRECTION_PORT_DUAL = (DIRECTION_PORT_DUAL & ~DIRECTION_MASK_DUAL) | (st.dir_outbits_dual & DIRECTION_MASK_DUAL); |
| 327 | #endif |
| 328 | |
| 329 | // Then pulse the stepping pins |
| 330 | #ifdef STEP_PULSE_DELAY |
| 331 | st.step_bits = (STEP_PORT & ~STEP_MASK) | st.step_outbits; // Store out_bits to prevent overwriting. |
| 332 | #ifdef ENABLE_DUAL_AXIS |
| 333 | st.step_bits_dual = (STEP_PORT_DUAL & ~STEP_MASK_DUAL) | st.step_outbits_dual; |
| 334 | #endif |
| 335 | #else // Normal operation |
| 336 | STEP_PORT = (STEP_PORT & ~STEP_MASK) | st.step_outbits; |
| 337 | #ifdef ENABLE_DUAL_AXIS |
| 338 | STEP_PORT_DUAL = (STEP_PORT_DUAL & ~STEP_MASK_DUAL) | st.step_outbits_dual; |
| 339 | #endif |
| 340 | #endif |
| 341 | |
| 342 | // Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after |
| 343 | // exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler. |
| 344 | TCNT0 = st.step_pulse_time; // Reload Timer0 counter |
| 345 | TCCR0B = (1<<CS01); // Begin Timer0. Full speed, 1/8 prescaler |
| 346 | |
| 347 | busy = true; |
| 348 | sei(); // Re-enable interrupts to allow Stepper Port Reset Interrupt to fire on-time. |
| 349 | // NOTE: The remaining code in this ISR will finish before returning to main program. |
| 350 | |
| 351 | // If there is no step segment, attempt to pop one from the stepper buffer |
| 352 | if (st.exec_segment == NULL) { |
| 353 | // Anything in the buffer? If so, load and initialize next step segment. |
| 354 | if (segment_buffer_head != segment_buffer_tail) { |
| 355 | // Initialize new step segment and load number of steps to execute |
| 356 | st.exec_segment = &segment_buffer[segment_buffer_tail]; |
| 357 | |
| 358 | #ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 359 | // With AMASS is disabled, set timer prescaler for segments with slow step frequencies (< 250Hz). |
| 360 | TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (st.exec_segment->prescaler<<CS10); |
| 361 | #endif |
| 362 | |
| 363 | // Initialize step segment timing per step and load number of steps to execute. |
| 364 | OCR1A = st.exec_segment->cycles_per_tick; |
| 365 | st.step_count = st.exec_segment->n_step; // NOTE: Can sometimes be zero when moving slow. |
| 366 | // If the new segment starts a new planner block, initialize stepper variables and counters. |
| 367 | // NOTE: When the segment data index changes, this indicates a new planner block. |
| 368 | if ( st.exec_block_index != st.exec_segment->st_block_index ) { |
| 369 | st.exec_block_index = st.exec_segment->st_block_index; |
| 370 | st.exec_block = &st_block_buffer[st.exec_block_index]; |
| 371 | |
| 372 | // Initialize Bresenham line and distance counters |
| 373 | st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1); |
| 374 | } |
| 375 | st.dir_outbits = st.exec_block->direction_bits ^ dir_port_invert_mask; |
| 376 | #ifdef ENABLE_DUAL_AXIS |
| 377 | st.dir_outbits_dual = st.exec_block->direction_bits_dual ^ dir_port_invert_mask_dual; |
| 378 | #endif |
| 379 | |
| 380 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 381 | // With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level. |
| 382 | st.steps[X_AXIS] = st.exec_block->steps[X_AXIS] >> st.exec_segment->amass_level; |
| 383 | st.steps[Y_AXIS] = st.exec_block->steps[Y_AXIS] >> st.exec_segment->amass_level; |
| 384 | st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level; |
| 385 | #endif |
| 386 | |
| 387 | #ifdef VARIABLE_SPINDLE |
| 388 | // Set real-time spindle output as segment is loaded, just prior to the first step. |
| 389 | spindle_set_speed(st.exec_segment->spindle_pwm); |
| 390 | #endif |
| 391 | |
| 392 | } else { |
| 393 | // Segment buffer empty. Shutdown. |
| 394 | st_go_idle(); |
| 395 | #ifdef VARIABLE_SPINDLE |
| 396 | // Ensure pwm is set properly upon completion of rate-controlled motion. |
| 397 | if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); } |
| 398 | #endif |
| 399 | system_set_exec_state_flag(EXEC_CYCLE_STOP); // Flag main program for cycle end |
| 400 | return; // Nothing to do but exit. |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | |
| 405 | // Check probing state. |
| 406 | if (sys_probe_state == PROBE_ACTIVE) { probe_state_monitor(); } |
| 407 | |
| 408 | // Reset step out bits. |
| 409 | st.step_outbits = 0; |
| 410 | #ifdef ENABLE_DUAL_AXIS |
| 411 | st.step_outbits_dual = 0; |
| 412 | #endif |
| 413 | |
| 414 | // Execute step displacement profile by Bresenham line algorithm |
| 415 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 416 | st.counter_x += st.steps[X_AXIS]; |
| 417 | #else |
| 418 | st.counter_x += st.exec_block->steps[X_AXIS]; |
| 419 | #endif |
| 420 | if (st.counter_x > st.exec_block->step_event_count) { |
| 421 | st.step_outbits |= (1<<X_STEP_BIT); |
| 422 | #if defined(ENABLE_DUAL_AXIS) && (DUAL_AXIS_SELECT == X_AXIS) |
| 423 | st.step_outbits_dual = (1<<DUAL_STEP_BIT); |
| 424 | #endif |
| 425 | st.counter_x -= st.exec_block->step_event_count; |
| 426 | if (st.exec_block->direction_bits & (1<<X_DIRECTION_BIT)) { sys_position[X_AXIS]--; } |
| 427 | else { sys_position[X_AXIS]++; } |
| 428 | } |
| 429 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 430 | st.counter_y += st.steps[Y_AXIS]; |
| 431 | #else |
| 432 | st.counter_y += st.exec_block->steps[Y_AXIS]; |
| 433 | #endif |
| 434 | if (st.counter_y > st.exec_block->step_event_count) { |
| 435 | st.step_outbits |= (1<<Y_STEP_BIT); |
| 436 | #if defined(ENABLE_DUAL_AXIS) && (DUAL_AXIS_SELECT == Y_AXIS) |
| 437 | st.step_outbits_dual = (1<<DUAL_STEP_BIT); |
| 438 | #endif |
| 439 | st.counter_y -= st.exec_block->step_event_count; |
| 440 | if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) { sys_position[Y_AXIS]--; } |
| 441 | else { sys_position[Y_AXIS]++; } |
| 442 | } |
| 443 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 444 | st.counter_z += st.steps[Z_AXIS]; |
| 445 | #else |
| 446 | st.counter_z += st.exec_block->steps[Z_AXIS]; |
| 447 | #endif |
| 448 | if (st.counter_z > st.exec_block->step_event_count) { |
| 449 | st.step_outbits |= (1<<Z_STEP_BIT); |
| 450 | st.counter_z -= st.exec_block->step_event_count; |
| 451 | if (st.exec_block->direction_bits & (1<<Z_DIRECTION_BIT)) { sys_position[Z_AXIS]--; } |
| 452 | else { sys_position[Z_AXIS]++; } |
| 453 | } |
| 454 | |
| 455 | // During a homing cycle, lock out and prevent desired axes from moving. |
| 456 | if (sys.state == STATE_HOMING) { |
| 457 | st.step_outbits &= sys.homing_axis_lock; |
| 458 | #ifdef ENABLE_DUAL_AXIS |
| 459 | st.step_outbits_dual &= sys.homing_axis_lock_dual; |
| 460 | #endif |
| 461 | } |
| 462 | |
| 463 | st.step_count--; // Decrement step events count |
| 464 | if (st.step_count == 0) { |
| 465 | // Segment is complete. Discard current segment and advance segment indexing. |
| 466 | st.exec_segment = NULL; |
| 467 | if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; } |
| 468 | } |
| 469 | |
| 470 | st.step_outbits ^= step_port_invert_mask; // Apply step port invert mask |
| 471 | #ifdef ENABLE_DUAL_AXIS |
| 472 | st.step_outbits_dual ^= step_port_invert_mask_dual; |
| 473 | #endif |
| 474 | busy = false; |
| 475 | } |
| 476 | |
| 477 | |
| 478 | /* The Stepper Port Reset Interrupt: Timer0 OVF interrupt handles the falling edge of the step |
| 479 | pulse. This should always trigger before the next Timer1 COMPA interrupt and independently |
| 480 | finish, if Timer1 is disabled after completing a move. |
| 481 | NOTE: Interrupt collisions between the serial and stepper interrupts can cause delays by |
| 482 | a few microseconds, if they execute right before one another. Not a big deal, but can |
| 483 | cause issues at high step rates if another high frequency asynchronous interrupt is |
| 484 | added to Grbl. |
| 485 | */ |
| 486 | // This interrupt is enabled by ISR_TIMER1_COMPAREA when it sets the motor port bits to execute |
| 487 | // a step. This ISR resets the motor port after a short period (settings.pulse_microseconds) |
| 488 | // completing one step cycle. |
| 489 | ISR(TIMER0_OVF_vect) |
| 490 | { |
| 491 | // Reset stepping pins (leave the direction pins) |
| 492 | STEP_PORT = (STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK); |
| 493 | #ifdef ENABLE_DUAL_AXIS |
| 494 | STEP_PORT_DUAL = (STEP_PORT_DUAL & ~STEP_MASK_DUAL) | (step_port_invert_mask_dual & STEP_MASK_DUAL); |
| 495 | #endif |
| 496 | TCCR0B = 0; // Disable Timer0 to prevent re-entering this interrupt when it's not needed. |
| 497 | } |
| 498 | #ifdef STEP_PULSE_DELAY |
| 499 | // This interrupt is used only when STEP_PULSE_DELAY is enabled. Here, the step pulse is |
| 500 | // initiated after the STEP_PULSE_DELAY time period has elapsed. The ISR TIMER2_OVF interrupt |
| 501 | // will then trigger after the appropriate settings.pulse_microseconds, as in normal operation. |
| 502 | // The new timing between direction, step pulse, and step complete events are setup in the |
| 503 | // st_wake_up() routine. |
| 504 | ISR(TIMER0_COMPA_vect) |
| 505 | { |
| 506 | STEP_PORT = st.step_bits; // Begin step pulse. |
| 507 | #ifdef ENABLE_DUAL_AXIS |
| 508 | STEP_PORT_DUAL = st.step_bits_dual; |
| 509 | #endif |
| 510 | } |
| 511 | #endif |
| 512 | |
| 513 | |
| 514 | // Generates the step and direction port invert masks used in the Stepper Interrupt Driver. |
| 515 | void st_generate_step_dir_invert_masks() |
| 516 | { |
| 517 | uint8_t idx; |
| 518 | step_port_invert_mask = 0; |
| 519 | dir_port_invert_mask = 0; |
| 520 | for (idx=0; idx<N_AXIS; idx++) { |
| 521 | if (bit_istrue(settings.step_invert_mask,bit(idx))) { step_port_invert_mask |= get_step_pin_mask(idx); } |
| 522 | if (bit_istrue(settings.dir_invert_mask,bit(idx))) { dir_port_invert_mask |= get_direction_pin_mask(idx); } |
| 523 | } |
| 524 | #ifdef ENABLE_DUAL_AXIS |
| 525 | step_port_invert_mask_dual = 0; |
| 526 | dir_port_invert_mask_dual = 0; |
| 527 | // NOTE: Dual axis invert uses the N_AXIS bit to set step and direction invert pins. |
| 528 | if (bit_istrue(settings.step_invert_mask,bit(N_AXIS))) { step_port_invert_mask_dual = (1<<DUAL_STEP_BIT); } |
| 529 | if (bit_istrue(settings.dir_invert_mask,bit(N_AXIS))) { dir_port_invert_mask_dual = (1<<DUAL_DIRECTION_BIT); } |
| 530 | #endif |
| 531 | } |
| 532 | |
| 533 | |
| 534 | // Reset and clear stepper subsystem variables |
| 535 | void st_reset() |
| 536 | { |
| 537 | // Initialize stepper driver idle state. |
| 538 | st_go_idle(); |
| 539 | |
| 540 | // Initialize stepper algorithm variables. |
| 541 | memset(&prep, 0, sizeof(st_prep_t)); |
| 542 | memset(&st, 0, sizeof(stepper_t)); |
| 543 | st.exec_segment = NULL; |
| 544 | pl_block = NULL; // Planner block pointer used by segment buffer |
| 545 | segment_buffer_tail = 0; |
| 546 | segment_buffer_head = 0; // empty = tail |
| 547 | segment_next_head = 1; |
| 548 | busy = false; |
| 549 | |
| 550 | st_generate_step_dir_invert_masks(); |
| 551 | st.dir_outbits = dir_port_invert_mask; // Initialize direction bits to default. |
| 552 | |
| 553 | // Initialize step and direction port pins. |
| 554 | STEP_PORT = (STEP_PORT & ~STEP_MASK) | step_port_invert_mask; |
| 555 | DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | dir_port_invert_mask; |
| 556 | |
| 557 | #ifdef ENABLE_DUAL_AXIS |
| 558 | st.dir_outbits_dual = dir_port_invert_mask_dual; |
| 559 | STEP_PORT_DUAL = (STEP_PORT_DUAL & ~STEP_MASK_DUAL) | step_port_invert_mask_dual; |
| 560 | DIRECTION_PORT_DUAL = (DIRECTION_PORT_DUAL & ~DIRECTION_MASK_DUAL) | dir_port_invert_mask_dual; |
| 561 | #endif |
| 562 | } |
| 563 | |
| 564 | |
| 565 | // Initialize and start the stepper motor subsystem |
| 566 | void stepper_init() |
| 567 | { |
| 568 | // Configure step and direction interface pins |
| 569 | STEP_DDR |= STEP_MASK; |
| 570 | STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT; |
| 571 | DIRECTION_DDR |= DIRECTION_MASK; |
| 572 | |
| 573 | #ifdef ENABLE_DUAL_AXIS |
| 574 | STEP_DDR_DUAL |= STEP_MASK_DUAL; |
| 575 | DIRECTION_DDR_DUAL |= DIRECTION_MASK_DUAL; |
| 576 | #endif |
| 577 | |
| 578 | // Configure Timer 1: Stepper Driver Interrupt |
| 579 | TCCR1B &= ~(1<<WGM13); // waveform generation = 0100 = CTC |
| 580 | TCCR1B |= (1<<WGM12); |
| 581 | TCCR1A &= ~((1<<WGM11) | (1<<WGM10)); |
| 582 | TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0)); // Disconnect OC1 output |
| 583 | // TCCR1B = (TCCR1B & ~((1<<CS12) | (1<<CS11))) | (1<<CS10); // Set in st_go_idle(). |
| 584 | // TIMSK1 &= ~(1<<OCIE1A); // Set in st_go_idle(). |
| 585 | |
| 586 | // Configure Timer 0: Stepper Port Reset Interrupt |
| 587 | TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0)); // Disconnect OC0 outputs and OVF interrupt. |
| 588 | TCCR0A = 0; // Normal operation |
| 589 | TCCR0B = 0; // Disable Timer0 until needed |
| 590 | TIMSK0 |= (1<<TOIE0); // Enable Timer0 overflow interrupt |
| 591 | #ifdef STEP_PULSE_DELAY |
| 592 | TIMSK0 |= (1<<OCIE0A); // Enable Timer0 Compare Match A interrupt |
| 593 | #endif |
| 594 | } |
| 595 | |
| 596 | |
| 597 | // Called by planner_recalculate() when the executing block is updated by the new plan. |
| 598 | void st_update_plan_block_parameters() |
| 599 | { |
| 600 | if (pl_block != NULL) { // Ignore if at start of a new block. |
| 601 | prep.recalculate_flag |= PREP_FLAG_RECALCULATE; |
| 602 | pl_block->entry_speed_sqr = prep.current_speed*prep.current_speed; // Update entry speed. |
| 603 | pl_block = NULL; // Flag st_prep_segment() to load and check active velocity profile. |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | |
| 608 | // Increments the step segment buffer block data ring buffer. |
| 609 | static uint8_t st_next_block_index(uint8_t block_index) |
| 610 | { |
| 611 | block_index++; |
| 612 | if ( block_index == (SEGMENT_BUFFER_SIZE-1) ) { return(0); } |
| 613 | return(block_index); |
| 614 | } |
| 615 | |
| 616 | |
| 617 | #ifdef PARKING_ENABLE |
| 618 | // Changes the run state of the step segment buffer to execute the special parking motion. |
| 619 | void st_parking_setup_buffer() |
| 620 | { |
| 621 | // Store step execution data of partially completed block, if necessary. |
| 622 | if (prep.recalculate_flag & PREP_FLAG_HOLD_PARTIAL_BLOCK) { |
| 623 | prep.last_st_block_index = prep.st_block_index; |
| 624 | prep.last_steps_remaining = prep.steps_remaining; |
| 625 | prep.last_dt_remainder = prep.dt_remainder; |
| 626 | prep.last_step_per_mm = prep.step_per_mm; |
| 627 | } |
| 628 | // Set flags to execute a parking motion |
| 629 | prep.recalculate_flag |= PREP_FLAG_PARKING; |
| 630 | prep.recalculate_flag &= ~(PREP_FLAG_RECALCULATE); |
| 631 | pl_block = NULL; // Always reset parking motion to reload new block. |
| 632 | } |
| 633 | |
| 634 | |
| 635 | // Restores the step segment buffer to the normal run state after a parking motion. |
| 636 | void st_parking_restore_buffer() |
| 637 | { |
| 638 | // Restore step execution data and flags of partially completed block, if necessary. |
| 639 | if (prep.recalculate_flag & PREP_FLAG_HOLD_PARTIAL_BLOCK) { |
| 640 | st_prep_block = &st_block_buffer[prep.last_st_block_index]; |
| 641 | prep.st_block_index = prep.last_st_block_index; |
| 642 | prep.steps_remaining = prep.last_steps_remaining; |
| 643 | prep.dt_remainder = prep.last_dt_remainder; |
| 644 | prep.step_per_mm = prep.last_step_per_mm; |
| 645 | prep.recalculate_flag = (PREP_FLAG_HOLD_PARTIAL_BLOCK | PREP_FLAG_RECALCULATE); |
| 646 | prep.req_mm_increment = REQ_MM_INCREMENT_SCALAR/prep.step_per_mm; // Recompute this value. |
| 647 | } else { |
| 648 | prep.recalculate_flag = false; |
| 649 | } |
| 650 | pl_block = NULL; // Set to reload next block. |
| 651 | } |
| 652 | #endif |
| 653 | |
| 654 | |
| 655 | /* Prepares step segment buffer. Continuously called from main program. |
| 656 | |
| 657 | The segment buffer is an intermediary buffer interface between the execution of steps |
| 658 | by the stepper algorithm and the velocity profiles generated by the planner. The stepper |
| 659 | algorithm only executes steps within the segment buffer and is filled by the main program |
| 660 | when steps are "checked-out" from the first block in the planner buffer. This keeps the |
| 661 | step execution and planning optimization processes atomic and protected from each other. |
| 662 | The number of steps "checked-out" from the planner buffer and the number of segments in |
| 663 | the segment buffer is sized and computed such that no operation in the main program takes |
| 664 | longer than the time it takes the stepper algorithm to empty it before refilling it. |
| 665 | Currently, the segment buffer conservatively holds roughly up to 40-50 msec of steps. |
| 666 | NOTE: Computation units are in steps, millimeters, and minutes. |
| 667 | */ |
| 668 | void st_prep_buffer() |
| 669 | { |
| 670 | // Block step prep buffer, while in a suspend state and there is no suspend motion to execute. |
| 671 | if (bit_istrue(sys.step_control,STEP_CONTROL_END_MOTION)) { return; } |
| 672 | |
| 673 | while (segment_buffer_tail != segment_next_head) { // Check if we need to fill the buffer. |
| 674 | |
| 675 | // Determine if we need to load a new planner block or if the block needs to be recomputed. |
| 676 | if (pl_block == NULL) { |
| 677 | |
| 678 | // Query planner for a queued block |
| 679 | if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) { pl_block = plan_get_system_motion_block(); } |
| 680 | else { pl_block = plan_get_current_block(); } |
| 681 | if (pl_block == NULL) { return; } // No planner blocks. Exit. |
| 682 | |
| 683 | // Check if we need to only recompute the velocity profile or load a new block. |
| 684 | if (prep.recalculate_flag & PREP_FLAG_RECALCULATE) { |
| 685 | |
| 686 | #ifdef PARKING_ENABLE |
| 687 | if (prep.recalculate_flag & PREP_FLAG_PARKING) { prep.recalculate_flag &= ~(PREP_FLAG_RECALCULATE); } |
| 688 | else { prep.recalculate_flag = false; } |
| 689 | #else |
| 690 | prep.recalculate_flag = false; |
| 691 | #endif |
| 692 | |
| 693 | } else { |
| 694 | |
| 695 | // Load the Bresenham stepping data for the block. |
| 696 | prep.st_block_index = st_next_block_index(prep.st_block_index); |
| 697 | |
| 698 | // Prepare and copy Bresenham algorithm segment data from the new planner block, so that |
| 699 | // when the segment buffer completes the planner block, it may be discarded when the |
| 700 | // segment buffer finishes the prepped block, but the stepper ISR is still executing it. |
| 701 | st_prep_block = &st_block_buffer[prep.st_block_index]; |
| 702 | st_prep_block->direction_bits = pl_block->direction_bits; |
| 703 | #ifdef ENABLE_DUAL_AXIS |
| 704 | #if (DUAL_AXIS_SELECT == X_AXIS) |
| 705 | if (st_prep_block->direction_bits & (1<<X_DIRECTION_BIT)) { |
| 706 | #elif (DUAL_AXIS_SELECT == Y_AXIS) |
| 707 | if (st_prep_block->direction_bits & (1<<Y_DIRECTION_BIT)) { |
| 708 | #endif |
| 709 | st_prep_block->direction_bits_dual = (1<<DUAL_DIRECTION_BIT); |
| 710 | } else { st_prep_block->direction_bits_dual = 0; } |
| 711 | #endif |
| 712 | uint8_t idx; |
| 713 | #ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 714 | for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = (pl_block->steps[idx] << 1); } |
| 715 | st_prep_block->step_event_count = (pl_block->step_event_count << 1); |
| 716 | #else |
| 717 | // With AMASS enabled, simply bit-shift multiply all Bresenham data by the max AMASS |
| 718 | // level, such that we never divide beyond the original data anywhere in the algorithm. |
| 719 | // If the original data is divided, we can lose a step from integer roundoff. |
| 720 | for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx] << MAX_AMASS_LEVEL; } |
| 721 | st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL; |
| 722 | #endif |
| 723 | |
| 724 | // Initialize segment buffer data for generating the segments. |
| 725 | prep.steps_remaining = (float)pl_block->step_event_count; |
| 726 | prep.step_per_mm = prep.steps_remaining/pl_block->millimeters; |
| 727 | prep.req_mm_increment = REQ_MM_INCREMENT_SCALAR/prep.step_per_mm; |
| 728 | prep.dt_remainder = 0.0; // Reset for new segment block |
| 729 | |
| 730 | if ((sys.step_control & STEP_CONTROL_EXECUTE_HOLD) || (prep.recalculate_flag & PREP_FLAG_DECEL_OVERRIDE)) { |
| 731 | // New block loaded mid-hold. Override planner block entry speed to enforce deceleration. |
| 732 | prep.current_speed = prep.exit_speed; |
| 733 | pl_block->entry_speed_sqr = prep.exit_speed*prep.exit_speed; |
| 734 | prep.recalculate_flag &= ~(PREP_FLAG_DECEL_OVERRIDE); |
| 735 | } else { |
| 736 | prep.current_speed = sqrt(pl_block->entry_speed_sqr); |
| 737 | } |
| 738 | |
| 739 | #ifdef VARIABLE_SPINDLE |
| 740 | // Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the |
| 741 | // spindle off. |
| 742 | st_prep_block->is_pwm_rate_adjusted = false; |
| 743 | if (settings.flags & BITFLAG_LASER_MODE) { |
| 744 | if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) { |
| 745 | // Pre-compute inverse programmed rate to speed up PWM updating per step segment. |
| 746 | prep.inv_rate = 1.0/pl_block->programmed_rate; |
| 747 | st_prep_block->is_pwm_rate_adjusted = true; |
| 748 | } |
| 749 | } |
| 750 | #endif |
| 751 | } |
| 752 | |
| 753 | /* --------------------------------------------------------------------------------- |
| 754 | Compute the velocity profile of a new planner block based on its entry and exit |
| 755 | speeds, or recompute the profile of a partially-completed planner block if the |
| 756 | planner has updated it. For a commanded forced-deceleration, such as from a feed |
| 757 | hold, override the planner velocities and decelerate to the target exit speed. |
| 758 | */ |
| 759 | prep.mm_complete = 0.0; // Default velocity profile complete at 0.0mm from end of block. |
| 760 | float inv_2_accel = 0.5/pl_block->acceleration; |
| 761 | if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { // [Forced Deceleration to Zero Velocity] |
| 762 | // Compute velocity profile parameters for a feed hold in-progress. This profile overrides |
| 763 | // the planner block profile, enforcing a deceleration to zero speed. |
| 764 | prep.ramp_type = RAMP_DECEL; |
| 765 | // Compute decelerate distance relative to end of block. |
| 766 | float decel_dist = pl_block->millimeters - inv_2_accel*pl_block->entry_speed_sqr; |
| 767 | if (decel_dist < 0.0) { |
| 768 | // Deceleration through entire planner block. End of feed hold is not in this block. |
| 769 | prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters); |
| 770 | } else { |
| 771 | prep.mm_complete = decel_dist; // End of feed hold. |
| 772 | prep.exit_speed = 0.0; |
| 773 | } |
| 774 | } else { // [Normal Operation] |
| 775 | // Compute or recompute velocity profile parameters of the prepped planner block. |
| 776 | prep.ramp_type = RAMP_ACCEL; // Initialize as acceleration ramp. |
| 777 | prep.accelerate_until = pl_block->millimeters; |
| 778 | |
| 779 | float exit_speed_sqr; |
| 780 | float nominal_speed; |
| 781 | if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) { |
| 782 | prep.exit_speed = exit_speed_sqr = 0.0; // Enforce stop at end of system motion. |
| 783 | } else { |
| 784 | exit_speed_sqr = plan_get_exec_block_exit_speed_sqr(); |
| 785 | prep.exit_speed = sqrt(exit_speed_sqr); |
| 786 | } |
| 787 | |
| 788 | nominal_speed = plan_compute_profile_nominal_speed(pl_block); |
| 789 | float nominal_speed_sqr = nominal_speed*nominal_speed; |
| 790 | float intersect_distance = |
| 791 | 0.5*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr)); |
| 792 | |
| 793 | if (pl_block->entry_speed_sqr > nominal_speed_sqr) { // Only occurs during override reductions. |
| 794 | prep.accelerate_until = pl_block->millimeters - inv_2_accel*(pl_block->entry_speed_sqr-nominal_speed_sqr); |
| 795 | if (prep.accelerate_until <= 0.0) { // Deceleration-only. |
| 796 | prep.ramp_type = RAMP_DECEL; |
| 797 | // prep.decelerate_after = pl_block->millimeters; |
| 798 | // prep.maximum_speed = prep.current_speed; |
| 799 | |
| 800 | // Compute override block exit speed since it doesn't match the planner exit speed. |
| 801 | prep.exit_speed = sqrt(pl_block->entry_speed_sqr - 2*pl_block->acceleration*pl_block->millimeters); |
| 802 | prep.recalculate_flag |= PREP_FLAG_DECEL_OVERRIDE; // Flag to load next block as deceleration override. |
| 803 | |
| 804 | // TODO: Determine correct handling of parameters in deceleration-only. |
| 805 | // Can be tricky since entry speed will be current speed, as in feed holds. |
| 806 | // Also, look into near-zero speed handling issues with this. |
| 807 | |
| 808 | } else { |
| 809 | // Decelerate to cruise or cruise-decelerate types. Guaranteed to intersect updated plan. |
| 810 | prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr); // Should always be >= 0.0 due to planner reinit. |
| 811 | prep.maximum_speed = nominal_speed; |
| 812 | prep.ramp_type = RAMP_DECEL_OVERRIDE; |
| 813 | } |
| 814 | } else if (intersect_distance > 0.0) { |
| 815 | if (intersect_distance < pl_block->millimeters) { // Either trapezoid or triangle types |
| 816 | // NOTE: For acceleration-cruise and cruise-only types, following calculation will be 0.0. |
| 817 | prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr); |
| 818 | if (prep.decelerate_after < intersect_distance) { // Trapezoid type |
| 819 | prep.maximum_speed = nominal_speed; |
| 820 | if (pl_block->entry_speed_sqr == nominal_speed_sqr) { |
| 821 | // Cruise-deceleration or cruise-only type. |
| 822 | prep.ramp_type = RAMP_CRUISE; |
| 823 | } else { |
| 824 | // Full-trapezoid or acceleration-cruise types |
| 825 | prep.accelerate_until -= inv_2_accel*(nominal_speed_sqr-pl_block->entry_speed_sqr); |
| 826 | } |
| 827 | } else { // Triangle type |
| 828 | prep.accelerate_until = intersect_distance; |
| 829 | prep.decelerate_after = intersect_distance; |
| 830 | prep.maximum_speed = sqrt(2.0*pl_block->acceleration*intersect_distance+exit_speed_sqr); |
| 831 | } |
| 832 | } else { // Deceleration-only type |
| 833 | prep.ramp_type = RAMP_DECEL; |
| 834 | // prep.decelerate_after = pl_block->millimeters; |
| 835 | // prep.maximum_speed = prep.current_speed; |
| 836 | } |
| 837 | } else { // Acceleration-only type |
| 838 | prep.accelerate_until = 0.0; |
| 839 | // prep.decelerate_after = 0.0; |
| 840 | prep.maximum_speed = prep.exit_speed; |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | #ifdef VARIABLE_SPINDLE |
| 845 | bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM); // Force update whenever updating block. |
| 846 | #endif |
| 847 | } |
| 848 | |
| 849 | // Initialize new segment |
| 850 | segment_t *prep_segment = &segment_buffer[segment_buffer_head]; |
| 851 | |
| 852 | // Set new segment to point to the current segment data block. |
| 853 | prep_segment->st_block_index = prep.st_block_index; |
| 854 | |
| 855 | /*------------------------------------------------------------------------------------ |
| 856 | Compute the average velocity of this new segment by determining the total distance |
| 857 | traveled over the segment time DT_SEGMENT. The following code first attempts to create |
| 858 | a full segment based on the current ramp conditions. If the segment time is incomplete |
| 859 | when terminating at a ramp state change, the code will continue to loop through the |
| 860 | progressing ramp states to fill the remaining segment execution time. However, if |
| 861 | an incomplete segment terminates at the end of the velocity profile, the segment is |
| 862 | considered completed despite having a truncated execution time less than DT_SEGMENT. |
| 863 | The velocity profile is always assumed to progress through the ramp sequence: |
| 864 | acceleration ramp, cruising state, and deceleration ramp. Each ramp's travel distance |
| 865 | may range from zero to the length of the block. Velocity profiles can end either at |
| 866 | the end of planner block (typical) or mid-block at the end of a forced deceleration, |
| 867 | such as from a feed hold. |
| 868 | */ |
| 869 | float dt_max = DT_SEGMENT; // Maximum segment time |
| 870 | float dt = 0.0; // Initialize segment time |
| 871 | float time_var = dt_max; // Time worker variable |
| 872 | float mm_var; // mm-Distance worker variable |
| 873 | float speed_var; // Speed worker variable |
| 874 | float mm_remaining = pl_block->millimeters; // New segment distance from end of block. |
| 875 | float minimum_mm = mm_remaining-prep.req_mm_increment; // Guarantee at least one step. |
| 876 | if (minimum_mm < 0.0) { minimum_mm = 0.0; } |
| 877 | |
| 878 | do { |
| 879 | switch (prep.ramp_type) { |
| 880 | case RAMP_DECEL_OVERRIDE: |
| 881 | speed_var = pl_block->acceleration*time_var; |
| 882 | if (prep.current_speed-prep.maximum_speed <= speed_var) { |
| 883 | // Cruise or cruise-deceleration types only for deceleration override. |
| 884 | mm_remaining = prep.accelerate_until; |
| 885 | time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed); |
| 886 | prep.ramp_type = RAMP_CRUISE; |
| 887 | prep.current_speed = prep.maximum_speed; |
| 888 | } else { // Mid-deceleration override ramp. |
| 889 | mm_remaining -= time_var*(prep.current_speed - 0.5*speed_var); |
| 890 | prep.current_speed -= speed_var; |
| 891 | } |
| 892 | break; |
| 893 | case RAMP_ACCEL: |
| 894 | // NOTE: Acceleration ramp only computes during first do-while loop. |
| 895 | speed_var = pl_block->acceleration*time_var; |
| 896 | mm_remaining -= time_var*(prep.current_speed + 0.5*speed_var); |
| 897 | if (mm_remaining < prep.accelerate_until) { // End of acceleration ramp. |
| 898 | // Acceleration-cruise, acceleration-deceleration ramp junction, or end of block. |
| 899 | mm_remaining = prep.accelerate_until; // NOTE: 0.0 at EOB |
| 900 | time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed); |
| 901 | if (mm_remaining == prep.decelerate_after) { prep.ramp_type = RAMP_DECEL; } |
| 902 | else { prep.ramp_type = RAMP_CRUISE; } |
| 903 | prep.current_speed = prep.maximum_speed; |
| 904 | } else { // Acceleration only. |
| 905 | prep.current_speed += speed_var; |
| 906 | } |
| 907 | break; |
| 908 | case RAMP_CRUISE: |
| 909 | // NOTE: mm_var used to retain the last mm_remaining for incomplete segment time_var calculations. |
| 910 | // NOTE: If maximum_speed*time_var value is too low, round-off can cause mm_var to not change. To |
| 911 | // prevent this, simply enforce a minimum speed threshold in the planner. |
| 912 | mm_var = mm_remaining - prep.maximum_speed*time_var; |
| 913 | if (mm_var < prep.decelerate_after) { // End of cruise. |
| 914 | // Cruise-deceleration junction or end of block. |
| 915 | time_var = (mm_remaining - prep.decelerate_after)/prep.maximum_speed; |
| 916 | mm_remaining = prep.decelerate_after; // NOTE: 0.0 at EOB |
| 917 | prep.ramp_type = RAMP_DECEL; |
| 918 | } else { // Cruising only. |
| 919 | mm_remaining = mm_var; |
| 920 | } |
| 921 | break; |
| 922 | default: // case RAMP_DECEL: |
| 923 | // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed. |
| 924 | speed_var = pl_block->acceleration*time_var; // Used as delta speed (mm/min) |
| 925 | if (prep.current_speed > speed_var) { // Check if at or below zero speed. |
| 926 | // Compute distance from end of segment to end of block. |
| 927 | mm_var = mm_remaining - time_var*(prep.current_speed - 0.5*speed_var); // (mm) |
| 928 | if (mm_var > prep.mm_complete) { // Typical case. In deceleration ramp. |
| 929 | mm_remaining = mm_var; |
| 930 | prep.current_speed -= speed_var; |
| 931 | break; // Segment complete. Exit switch-case statement. Continue do-while loop. |
| 932 | } |
| 933 | } |
| 934 | // Otherwise, at end of block or end of forced-deceleration. |
| 935 | time_var = 2.0*(mm_remaining-prep.mm_complete)/(prep.current_speed+prep.exit_speed); |
| 936 | mm_remaining = prep.mm_complete; |
| 937 | prep.current_speed = prep.exit_speed; |
| 938 | } |
| 939 | dt += time_var; // Add computed ramp time to total segment time. |
| 940 | if (dt < dt_max) { time_var = dt_max - dt; } // **Incomplete** At ramp junction. |
| 941 | else { |
| 942 | if (mm_remaining > minimum_mm) { // Check for very slow segments with zero steps. |
| 943 | // Increase segment time to ensure at least one step in segment. Override and loop |
| 944 | // through distance calculations until minimum_mm or mm_complete. |
| 945 | dt_max += DT_SEGMENT; |
| 946 | time_var = dt_max - dt; |
| 947 | } else { |
| 948 | break; // **Complete** Exit loop. Segment execution time maxed. |
| 949 | } |
| 950 | } |
| 951 | } while (mm_remaining > prep.mm_complete); // **Complete** Exit loop. Profile complete. |
| 952 | |
| 953 | #ifdef VARIABLE_SPINDLE |
| 954 | /* ----------------------------------------------------------------------------------- |
| 955 | Compute spindle speed PWM output for step segment |
| 956 | */ |
| 957 | |
| 958 | if (st_prep_block->is_pwm_rate_adjusted || (sys.step_control & STEP_CONTROL_UPDATE_SPINDLE_PWM)) { |
| 959 | if (pl_block->condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)) { |
| 960 | float rpm = pl_block->spindle_speed; |
| 961 | // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate. |
| 962 | if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); } |
| 963 | // If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE) |
| 964 | // but this would be instantaneous only and during a motion. May not matter at all. |
| 965 | prep.current_spindle_pwm = spindle_compute_pwm_value(rpm); |
| 966 | } else { |
| 967 | sys.spindle_speed = 0.0; |
| 968 | prep.current_spindle_pwm = SPINDLE_PWM_OFF_VALUE; |
| 969 | } |
| 970 | bit_false(sys.step_control,STEP_CONTROL_UPDATE_SPINDLE_PWM); |
| 971 | } |
| 972 | prep_segment->spindle_pwm = prep.current_spindle_pwm; // Reload segment PWM value |
| 973 | |
| 974 | #endif |
| 975 | |
| 976 | /* ----------------------------------------------------------------------------------- |
| 977 | Compute segment step rate, steps to execute, and apply necessary rate corrections. |
| 978 | NOTE: Steps are computed by direct scalar conversion of the millimeter distance |
| 979 | remaining in the block, rather than incrementally tallying the steps executed per |
| 980 | segment. This helps in removing floating point round-off issues of several additions. |
| 981 | However, since floats have only 7.2 significant digits, long moves with extremely |
| 982 | high step counts can exceed the precision of floats, which can lead to lost steps. |
| 983 | Fortunately, this scenario is highly unlikely and unrealistic in CNC machines |
| 984 | supported by Grbl (i.e. exceeding 10 meters axis travel at 200 step/mm). |
| 985 | */ |
| 986 | float step_dist_remaining = prep.step_per_mm*mm_remaining; // Convert mm_remaining to steps |
| 987 | float n_steps_remaining = ceil(step_dist_remaining); // Round-up current steps remaining |
| 988 | float last_n_steps_remaining = ceil(prep.steps_remaining); // Round-up last steps remaining |
| 989 | prep_segment->n_step = last_n_steps_remaining-n_steps_remaining; // Compute number of steps to execute. |
| 990 | |
| 991 | // Bail if we are at the end of a feed hold and don't have a step to execute. |
| 992 | if (prep_segment->n_step == 0) { |
| 993 | if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { |
| 994 | // Less than one step to decelerate to zero speed, but already very close. AMASS |
| 995 | // requires full steps to execute. So, just bail. |
| 996 | bit_true(sys.step_control,STEP_CONTROL_END_MOTION); |
| 997 | #ifdef PARKING_ENABLE |
| 998 | if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) { prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK; } |
| 999 | #endif |
| 1000 | return; // Segment not generated, but current step data still retained. |
| 1001 | } |
| 1002 | } |
| 1003 | |
| 1004 | // Compute segment step rate. Since steps are integers and mm distances traveled are not, |
| 1005 | // the end of every segment can have a partial step of varying magnitudes that are not |
| 1006 | // executed, because the stepper ISR requires whole steps due to the AMASS algorithm. To |
| 1007 | // compensate, we track the time to execute the previous segment's partial step and simply |
| 1008 | // apply it with the partial step distance to the current segment, so that it minutely |
| 1009 | // adjusts the whole segment rate to keep step output exact. These rate adjustments are |
| 1010 | // typically very small and do not adversely effect performance, but ensures that Grbl |
| 1011 | // outputs the exact acceleration and velocity profiles as computed by the planner. |
| 1012 | dt += prep.dt_remainder; // Apply previous segment partial step execute time |
| 1013 | float inv_rate = dt/(last_n_steps_remaining - step_dist_remaining); // Compute adjusted step rate inverse |
| 1014 | |
| 1015 | // Compute CPU cycles per step for the prepped segment. |
| 1016 | uint32_t cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate ); // (cycles/step) |
| 1017 | |
| 1018 | #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING |
| 1019 | // Compute step timing and multi-axis smoothing level. |
| 1020 | // NOTE: AMASS overdrives the timer with each level, so only one prescalar is required. |
| 1021 | if (cycles < AMASS_LEVEL1) { prep_segment->amass_level = 0; } |
| 1022 | else { |
| 1023 | if (cycles < AMASS_LEVEL2) { prep_segment->amass_level = 1; } |
| 1024 | else if (cycles < AMASS_LEVEL3) { prep_segment->amass_level = 2; } |
| 1025 | else { prep_segment->amass_level = 3; } |
| 1026 | cycles >>= prep_segment->amass_level; |
| 1027 | prep_segment->n_step <<= prep_segment->amass_level; |
| 1028 | } |
| 1029 | if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; } // < 65536 (4.1ms @ 16MHz) |
| 1030 | else { prep_segment->cycles_per_tick = 0xffff; } // Just set the slowest speed possible. |
| 1031 | #else |
| 1032 | // Compute step timing and timer prescalar for normal step generation. |
| 1033 | if (cycles < (1UL << 16)) { // < 65536 (4.1ms @ 16MHz) |
| 1034 | prep_segment->prescaler = 1; // prescaler: 0 |
| 1035 | prep_segment->cycles_per_tick = cycles; |
| 1036 | } else if (cycles < (1UL << 19)) { // < 524288 (32.8ms@16MHz) |
| 1037 | prep_segment->prescaler = 2; // prescaler: 8 |
| 1038 | prep_segment->cycles_per_tick = cycles >> 3; |
| 1039 | } else { |
| 1040 | prep_segment->prescaler = 3; // prescaler: 64 |
| 1041 | if (cycles < (1UL << 22)) { // < 4194304 (262ms@16MHz) |
| 1042 | prep_segment->cycles_per_tick = cycles >> 6; |
| 1043 | } else { // Just set the slowest speed possible. (Around 4 step/sec.) |
| 1044 | prep_segment->cycles_per_tick = 0xffff; |
| 1045 | } |
| 1046 | } |
| 1047 | #endif |
| 1048 | |
| 1049 | // Segment complete! Increment segment buffer indices, so stepper ISR can immediately execute it. |
| 1050 | segment_buffer_head = segment_next_head; |
| 1051 | if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; } |
| 1052 | |
| 1053 | // Update the appropriate planner and segment data. |
| 1054 | pl_block->millimeters = mm_remaining; |
| 1055 | prep.steps_remaining = n_steps_remaining; |
| 1056 | prep.dt_remainder = (n_steps_remaining - step_dist_remaining)*inv_rate; |
| 1057 | |
| 1058 | // Check for exit conditions and flag to load next planner block. |
| 1059 | if (mm_remaining == prep.mm_complete) { |
| 1060 | // End of planner block or forced-termination. No more distance to be executed. |
| 1061 | if (mm_remaining > 0.0) { // At end of forced-termination. |
| 1062 | // Reset prep parameters for resuming and then bail. Allow the stepper ISR to complete |
| 1063 | // the segment queue, where realtime protocol will set new state upon receiving the |
| 1064 | // cycle stop flag from the ISR. Prep_segment is blocked until then. |
| 1065 | bit_true(sys.step_control,STEP_CONTROL_END_MOTION); |
| 1066 | #ifdef PARKING_ENABLE |
| 1067 | if (!(prep.recalculate_flag & PREP_FLAG_PARKING)) { prep.recalculate_flag |= PREP_FLAG_HOLD_PARTIAL_BLOCK; } |
| 1068 | #endif |
| 1069 | return; // Bail! |
| 1070 | } else { // End of planner block |
| 1071 | // The planner block is complete. All steps are set to be executed in the segment buffer. |
| 1072 | if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) { |
| 1073 | bit_true(sys.step_control,STEP_CONTROL_END_MOTION); |
| 1074 | return; |
| 1075 | } |
| 1076 | pl_block = NULL; // Set pointer to indicate check and load next planner block. |
| 1077 | plan_discard_current_block(); |
| 1078 | } |
| 1079 | } |
| 1080 | |
| 1081 | } |
| 1082 | } |
| 1083 | |
| 1084 | |
| 1085 | // Called by realtime status reporting to fetch the current speed being executed. This value |
| 1086 | // however is not exactly the current speed, but the speed computed in the last step segment |
| 1087 | // in the segment buffer. It will always be behind by up to the number of segment blocks (-1) |
| 1088 | // divided by the ACCELERATION TICKS PER SECOND in seconds. |
| 1089 | float st_get_realtime_rate() |
| 1090 | { |
| 1091 | if (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)){ |
| 1092 | return prep.current_speed; |
| 1093 | } |
| 1094 | return 0.0f; |
| 1095 | } |