gnea\grbl-Mega  1.0f
Source Code Documentation ( Internal Workings )
stepper.c
Go to the documentation of this file.
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 
25 #define DT_SEGMENT (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0))
26 #define REQ_MM_INCREMENT_SCALAR 1.25
27 #define RAMP_ACCEL 0
28 #define RAMP_CRUISE 1
29 #define RAMP_DECEL 2
30 #define RAMP_DECEL_OVERRIDE 3
31 
32 #define PREP_FLAG_RECALCULATE bit(0)
33 #define PREP_FLAG_HOLD_PARTIAL_BLOCK bit(1)
34 #define PREP_FLAG_PARKING bit(2)
35 #define PREP_FLAG_DECEL_OVERRIDE bit(3)
36 
49 #define MAX_AMASS_LEVEL 3
50 // AMASS_LEVEL0: Normal operation. No AMASS. No upper cutoff frequency. Starts at LEVEL1 cutoff frequency.
51 #define AMASS_LEVEL1 (F_CPU/8000)
52 #define AMASS_LEVEL2 (F_CPU/4000)
53 #define AMASS_LEVEL3 (F_CPU/2000)
54 
55 // buffer. Normally, this buffer is partially in-use, but, for the worst case scenario, it will
57 // never exceed the number of accessible stepper buffer segments (SEGMENT_BUFFER_SIZE-1).
58 // NOTE: This data is copied from the prepped planner blocks so that the planner blocks may be
59 // discarded when entirely consumed and completed by the segment buffer. Also, AMASS alters this
60 // data for its own use.
61 typedef struct {
62  uint32_t steps[N_AXIS];
63  uint32_t step_event_count;
64  uint8_t direction_bits;
66 } st_block_t;
67 static st_block_t st_block_buffer[SEGMENT_BUFFER_SIZE-1];
68 
70 // algorithm to execute, which are "checked-out" incrementally from the first block in the
71 // planner buffer. Once "checked-out", the steps in the segments buffer cannot be modified by
72 // the planner, where the remaining planner block steps still can.
73 typedef struct {
74  uint16_t n_step;
75  uint16_t cycles_per_tick;
76  uint8_t st_block_index;
77  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
78  uint8_t amass_level;
79  #else
80  uint8_t prescaler;
81  #endif
82  uint16_t spindle_pwm;
83 } segment_t;
84 static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
85 
87 typedef struct {
88 // Used by the bresenham line algorithm
89  uint32_t counter_x,
90  counter_y,
91  counter_z;
92  #ifdef STEP_PULSE_DELAY
93  uint8_t step_bits;
94  #endif
95 
96  uint8_t execute_step;
97  uint8_t step_pulse_time;
98  uint8_t step_outbits;
99  uint8_t dir_outbits;
100  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
101  uint32_t steps[N_AXIS];
102  #endif
103 
104  uint16_t step_count;
108 } stepper_t;
109 static stepper_t st;
111 static volatile uint8_t segment_buffer_tail;
112 static uint8_t segment_buffer_head;
113 static uint8_t segment_next_head;
115 static uint8_t step_port_invert_mask;
116 static uint8_t dir_port_invert_mask;
118 static volatile uint8_t busy;
120 // main program. Pointers may be planning segments or planner blocks ahead of what being executed.
121 static plan_block_t *pl_block;
122 static st_block_t *st_prep_block;
123 // based on the current executing planner block.
125 typedef struct {
126  uint8_t st_block_index;
128 
131  float step_per_mm;
133 
134  #ifdef PARKING_ENABLE
135  uint8_t last_st_block_index;
136  float last_steps_remaining;
137  float last_step_per_mm;
138  float last_dt_remainder;
139  #endif
140 
141  uint8_t ramp_type;
142  float mm_complete;
143 // NOTE: This value must coincide with a step(no mantissa) when converted.
146  float exit_speed;
149 
150  float inv_rate;
152 } st_prep_t;
153 static st_prep_t prep;
154 
155 
197 // enabled. Startup init and limits call this function but shouldn't start the cycle.
200 {
201  // Enable stepper drivers.
202  if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }
203  else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }
204 
205  // Initialize stepper output bits to ensure first ISR call does not step.
206  st.step_outbits = step_port_invert_mask;
207 
208  // Initialize step pulse timing from settings. Here to ensure updating after re-writing.
209  #ifdef STEP_PULSE_DELAY
210  // Set total step pulse time after direction pin set. Ad hoc computation from oscilloscope.
211  st.step_pulse_time = -(((settings.pulse_microseconds+STEP_PULSE_DELAY-2)*TICKS_PER_MICROSECOND) >> 3);
212  // Set delay between direction pin write and step command.
214  #else
215  // Set step pulse time. Ad hoc computation from oscilloscope. Uses two's complement.
217  #endif
218 
219  // Enable Stepper Driver Interrupt
220  TIMSK1 |= (1<<OCIE1A);
221 }
222 
225 {
226  // Disable Stepper Driver Interrupt. Allow Stepper Port Reset Interrupt to finish, if active.
227  TIMSK1 &= ~(1<<OCIE1A);
228  TCCR1B = (TCCR1B & ~((1<<CS12) | (1<<CS11))) | (1<<CS10);
229  busy = false;
230 
231  // Set stepper driver idle state, disabled or enabled, depending on settings and circumstances.
232  bool pin_state = false;
234  // Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
235  // stop and not drift from residual inertial forces at the end of the last movement.
237  pin_state = true;
238  }
239  if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)) { pin_state = !pin_state; }
240  if (pin_state) { STEPPERS_DISABLE_PORT |= (1<<STEPPERS_DISABLE_BIT); }
241  else { STEPPERS_DISABLE_PORT &= ~(1<<STEPPERS_DISABLE_BIT); }
242 }
243 
244 
304 ISR(TIMER1_COMPA_vect)
305 {
306  if (busy) { return; }
307 
308  // Set the direction pins a couple of nanoseconds before we step the steppers
309  DIRECTION_PORT_SET((DIRECTION_PORT & ~DIRECTION_MASK) | (st.dir_outbits & DIRECTION_MASK));
310 
311  // Then pulse the stepping pins
312  #ifdef STEP_PULSE_DELAY
313  st.step_bits = (STEP_PORT & ~STEP_MASK) | st.step_outbits;
314  #else // Normal operation
315  STEP_PORT_SET((STEP_PORT & ~STEP_MASK) | st.step_outbits);
316  #endif
317 
318  // Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after
319  // exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler.
320  TCNT0 = st.step_pulse_time; // Reload Timer0 counter
321  TCCR0B = (1<<CS01); // Begin Timer0. Full speed, 1/8 prescaler
322 
323  busy = true;
324  sei(); // Re-enable interrupts to allow Stepper Port Reset Interrupt to fire on-time.
325  // NOTE: The remaining code in this ISR will finish before returning to main program.
326 
327  // If there is no step segment, attempt to pop one from the stepper buffer
328  if (st.exec_segment == NULL) {
329  // Anything in the buffer? If so, load and initialize next step segment.
330  if (segment_buffer_head != segment_buffer_tail) {
331  // Initialize new step segment and load number of steps to execute
332  st.exec_segment = &segment_buffer[segment_buffer_tail];
333 
334  #ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
335  // With AMASS is disabled, set timer prescaler for segments with slow step frequencies (< 250Hz).
336  TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (st.exec_segment->prescaler<<CS10);
337  #endif
338 
339  // Initialize step segment timing per step and load number of steps to execute.
340  OCR1A = st.exec_segment->cycles_per_tick;
341  st.step_count = st.exec_segment->n_step;
342  // If the new segment starts a new planner block, initialize stepper variables and counters.
343  // NOTE: When the segment data index changes, this indicates a new planner block.
344  if ( st.exec_block_index != st.exec_segment->st_block_index ) {
346  st.exec_block = &st_block_buffer[st.exec_block_index];
347 
348  // Initialize Bresenham line and distance counters
349  st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
350  }
351  st.dir_outbits = st.exec_block->direction_bits ^ dir_port_invert_mask;
352 
353  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
354  // With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level.
358  #endif
359 
360  // Set real-time spindle output as segment is loaded, just prior to the first step.
362 
363  } else {
364  // Segment buffer empty. Shutdown.
365  st_go_idle();
366  // Ensure pwm is set properly upon completion of rate-controlled motion.
367  if (st.exec_block->is_pwm_rate_adjusted) { spindle_set_speed(SPINDLE_PWM_OFF_VALUE); }
369  return;
370  }
371  }
372 
373 
374 // Check probing state.
376 
377 // Reset step out bits.
378  st.step_outbits = 0;
379 
380 // Execute step displacement profile by Bresenham line algorithm
381  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
382  st.counter_x += st.steps[X_AXIS];
383  #else
384  st.counter_x += st.exec_block->steps[X_AXIS];
385  #endif
386  if (st.counter_x > st.exec_block->step_event_count) {
387  st.step_outbits |= (1<<X_STEP_BIT);
389  if (st.exec_block->direction_bits & (1<<X_DIRECTION_BIT)) { sys_position[X_AXIS]--; }
390  else { sys_position[X_AXIS]++; }
391  }
392  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
393  st.counter_y += st.steps[Y_AXIS];
394  #else
395  st.counter_y += st.exec_block->steps[Y_AXIS];
396  #endif
397  if (st.counter_y > st.exec_block->step_event_count) {
398  st.step_outbits |= (1<<Y_STEP_BIT);
400  if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) { sys_position[Y_AXIS]--; }
401  else { sys_position[Y_AXIS]++; }
402  }
403  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
404  st.counter_z += st.steps[Z_AXIS];
405  #else
406  st.counter_z += st.exec_block->steps[Z_AXIS];
407  #endif
408  if (st.counter_z > st.exec_block->step_event_count) {
409  st.step_outbits |= (1<<Z_STEP_BIT);
411  if (st.exec_block->direction_bits & (1<<Z_DIRECTION_BIT)) { sys_position[Z_AXIS]--; }
412  else { sys_position[Z_AXIS]++; }
413  }
414 
415 // During a homing cycle, lock out and prevent desired axes from moving.
417 
418  st.step_count--;
419  if (st.step_count == 0) {
420 // Segment is complete. Discard current segment and advance segment indexing.
421  st.exec_segment = NULL;
422  if ( ++segment_buffer_tail == SEGMENT_BUFFER_SIZE) { segment_buffer_tail = 0; }
423  }
424 
425  st.step_outbits ^= step_port_invert_mask;
426  busy = false;
427 }
428 
429 
444 ISR(TIMER0_OVF_vect)
445 {
446 // Reset stepping pins (leave the direction pins)
447  STEP_PORT_SET((STEP_PORT & ~STEP_MASK) | (step_port_invert_mask & STEP_MASK));
448  TCCR0B = 0;
449 }
450 #ifdef STEP_PULSE_DELAY
451 
457  ISR(TIMER0_COMPA_vect)
458  {
459  STEP_PORT_SET(st.step_bits); // Begin step pulse.
460  }
461 #endif
462 
465 {
466  uint8_t idx;
467  step_port_invert_mask = 0;
468  dir_port_invert_mask = 0;
469  for (idx=0; idx<N_AXIS; idx++) {
470  if (bit_istrue(settings.step_invert_mask,bit(idx))) { step_port_invert_mask |= get_step_pin_mask(idx); }
471  if (bit_istrue(settings.dir_invert_mask,bit(idx))) { dir_port_invert_mask |= get_direction_pin_mask(idx); }
472  }
473 }
474 
476 void st_reset()
477 {
478 // Initialize stepper driver idle state.
479  st_go_idle();
480 
481 // Initialize stepper algorithm variables.
482  memset(&prep, 0, sizeof(st_prep_t));
483  memset(&st, 0, sizeof(stepper_t));
484  st.exec_segment = NULL;
485  pl_block = NULL;
486  segment_buffer_tail = 0;
487  segment_buffer_head = 0;
488  segment_next_head = 1;
489  busy = false;
490 
492  st.dir_outbits = dir_port_invert_mask;
493 
494 // Initialize step and direction port pins.
495  STEP_PORT_SET((STEP_PORT & ~STEP_MASK) | step_port_invert_mask);
496  DIRECTION_PORT_SET((DIRECTION_PORT & ~DIRECTION_MASK) | dir_port_invert_mask);
497 }
498 
501 {
502 // Configure step and direction interface pins
503  STEP_DDR |= STEP_MASK;
504  STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
505  DIRECTION_DDR |= DIRECTION_MASK;
506 
507 // Configure Timer 1: Stepper Driver Interrupt
508  TCCR1B &= ~(1<<WGM13);
509  TCCR1B |= (1<<WGM12);
510  TCCR1A &= ~((1<<WGM11) | (1<<WGM10));
511  TCCR1A &= ~((1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0));
512 // TCCR1B = (TCCR1B & ~((1<<CS12) | (1<<CS11))) | (1<<CS10); //!< Set in st_go_idle().
513 // TIMSK1 &= ~(1<<OCIE1A); //!< Set in st_go_idle().
514 
515 // Configure Timer 0: Stepper Port Reset Interrupt
516  TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0));
517  TCCR0A = 0;
518  TCCR0B = 0;
519  TIMSK0 |= (1<<TOIE0);
520  #ifdef STEP_PULSE_DELAY
521  TIMSK0 |= (1<<OCIE0A);
522  #endif
523 }
524 
527 {
528  if (pl_block != NULL) {
530  pl_block->entry_speed_sqr = prep.current_speed*prep.current_speed;
531  pl_block = NULL;
532  }
533 }
534 
536 static uint8_t st_next_block_index(uint8_t block_index)
537 {
538  block_index++;
539  if ( block_index == (SEGMENT_BUFFER_SIZE-1) ) { return(0); }
540  return(block_index);
541 }
542 
543 
544 #ifdef PARKING_ENABLE
545 // Changes the run state of the step segment buffer to execute the special parking motion.
547  {
548 // Store step execution data of partially completed block, if necessary.
550  prep.last_st_block_index = prep.st_block_index;
551  prep.last_steps_remaining = prep.steps_remaining;
552  prep.last_dt_remainder = prep.dt_remainder;
553  prep.last_step_per_mm = prep.step_per_mm;
554  }
555 // Set flags to execute a parking motion
558  pl_block = NULL;
559  }
560 
561 
562 // Restores the step segment buffer to the normal run state after a parking motion.
564  {
565 // Restore step execution data and flags of partially completed block, if necessary.
567  st_prep_block = &st_block_buffer[prep.last_st_block_index];
568  prep.st_block_index = prep.last_st_block_index;
569  prep.steps_remaining = prep.last_steps_remaining;
570  prep.dt_remainder = prep.last_dt_remainder;
571  prep.step_per_mm = prep.last_step_per_mm;
574  } else {
575  prep.recalculate_flag = false;
576  }
577  pl_block = NULL;
578  }
579 #endif
580 
595 {
596 // Block step prep buffer, while in a suspend state and there is no suspend motion to execute.
598 
599  while (segment_buffer_tail != segment_next_head) {
600 
601 // Determine if we need to load a new planner block or if the block needs to be recomputed.
602  if (pl_block == NULL) {
603 
604 // Query planner for a queued block
606  else { pl_block = plan_get_current_block(); }
607  if (pl_block == NULL) { return; }
608 
609 // Check if we need to only recompute the velocity profile or load a new block.
611 
612  #ifdef PARKING_ENABLE
614  else { prep.recalculate_flag = false; }
615  #else
616  prep.recalculate_flag = false;
617  #endif
618 
619  } else {
620 
621 // Load the Bresenham stepping data for the block.
622  prep.st_block_index = st_next_block_index(prep.st_block_index);
623 
624 // Prepare and copy Bresenham algorithm segment data from the new planner block, so that
625 // when the segment buffer completes the planner block, it may be discarded when the
626 // segment buffer finishes the prepped block, but the stepper ISR is still executing it.
627  st_prep_block = &st_block_buffer[prep.st_block_index];
628  st_prep_block->direction_bits = pl_block->direction_bits;
629  uint8_t idx;
630  #ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
631  for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx]; }
632  st_prep_block->step_event_count = pl_block->step_event_count;
633  #else
634 // With AMASS enabled, simply bit-shift multiply all Bresenham data by the max AMASS
635 // level, such that we never divide beyond the original data anywhere in the algorithm.
636 // If the original data is divided, we can lose a step from integer roundoff.
637  for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx] << MAX_AMASS_LEVEL; }
638  st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL;
639  #endif
640 
641 // Initialize segment buffer data for generating the segments.
642  prep.steps_remaining = (float)pl_block->step_event_count;
643  prep.step_per_mm = prep.steps_remaining/pl_block->millimeters;
645  prep.dt_remainder = 0.0;
646 
648 // New block loaded mid-hold. Override planner block entry speed to enforce deceleration.
649  prep.current_speed = prep.exit_speed;
650  pl_block->entry_speed_sqr = prep.exit_speed*prep.exit_speed;
652  } else {
653  prep.current_speed = sqrt(pl_block->entry_speed_sqr);
654  }
655 
656 // Setup laser mode variables. PWM rate adjusted motions will always complete a motion with the
657 // spindle off.
658  st_prep_block->is_pwm_rate_adjusted = false;
660  if (pl_block->condition & PL_COND_FLAG_SPINDLE_CCW) {
661 // Pre-compute inverse programmed rate to speed up PWM updating per step segment.
662  prep.inv_rate = 1.0/pl_block->programmed_rate;
663  st_prep_block->is_pwm_rate_adjusted = true;
664  }
665  }
666  }
667 
668  /* ---------------------------------------------------------------------------------
669  Compute the velocity profile of a new planner block based on its entry and exit
670  speeds, or recompute the profile of a partially-completed planner block if the
671  planner has updated it. For a commanded forced-deceleration, such as from a feed
672  hold, override the planner velocities and decelerate to the target exit speed.
673  */
674  prep.mm_complete = 0.0;
675  float inv_2_accel = 0.5/pl_block->acceleration;
677  // Compute velocity profile parameters for a feed hold in-progress. This profile overrides
678  // the planner block profile, enforcing a deceleration to zero speed.
679  prep.ramp_type = RAMP_DECEL;
680  // Compute decelerate distance relative to end of block.
681  float decel_dist = pl_block->millimeters - inv_2_accel*pl_block->entry_speed_sqr;
682  if (decel_dist < 0.0) {
683  // Deceleration through entire planner block. End of feed hold is not in this block.
684  prep.exit_speed = sqrt(pl_block->entry_speed_sqr-2*pl_block->acceleration*pl_block->millimeters);
685  } else {
686  prep.mm_complete = decel_dist;
687  prep.exit_speed = 0.0;
688  }
689  } else {
690  // Compute or recompute velocity profile parameters of the prepped planner block.
691  prep.ramp_type = RAMP_ACCEL;
692  prep.accelerate_until = pl_block->millimeters;
693 
694  float exit_speed_sqr;
695  float nominal_speed;
697  prep.exit_speed = exit_speed_sqr = 0.0;
698  } else {
699  exit_speed_sqr = plan_get_exec_block_exit_speed_sqr();
700  prep.exit_speed = sqrt(exit_speed_sqr);
701  }
702 
703  nominal_speed = plan_compute_profile_nominal_speed(pl_block);
704  float nominal_speed_sqr = nominal_speed*nominal_speed;
705  float intersect_distance =
706  0.5*(pl_block->millimeters+inv_2_accel*(pl_block->entry_speed_sqr-exit_speed_sqr));
707 
708  if (pl_block->entry_speed_sqr > nominal_speed_sqr) {
709  prep.accelerate_until = pl_block->millimeters - inv_2_accel*(pl_block->entry_speed_sqr-nominal_speed_sqr);
710  if (prep.accelerate_until <= 0.0) {
711  prep.ramp_type = RAMP_DECEL;
712 // prep.decelerate_after = pl_block->millimeters;
713 // prep.maximum_speed = prep.current_speed;
714 
715 // Compute override block exit speed since it doesn't match the planner exit speed.
716  prep.exit_speed = sqrt(pl_block->entry_speed_sqr - 2*pl_block->acceleration*pl_block->millimeters);
718 
720 // Can be tricky since entry speed will be current speed, as in feed holds.
721 // Also, look into near-zero speed handling issues with this.
722 
723  } else {
724 // Decelerate to cruise or cruise-decelerate types. Guaranteed to intersect updated plan.
725  prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
726  prep.maximum_speed = nominal_speed;
728  }
729  } else if (intersect_distance > 0.0) {
730  if (intersect_distance < pl_block->millimeters) {
731  // NOTE: For acceleration-cruise and cruise-only types, following calculation will be 0.0.
732  prep.decelerate_after = inv_2_accel*(nominal_speed_sqr-exit_speed_sqr);
733  if (prep.decelerate_after < intersect_distance) {
734  prep.maximum_speed = nominal_speed;
735  if (pl_block->entry_speed_sqr == nominal_speed_sqr) {
736  // Cruise-deceleration or cruise-only type.
737  prep.ramp_type = RAMP_CRUISE;
738  } else {
739  // Full-trapezoid or acceleration-cruise types
740  prep.accelerate_until -= inv_2_accel*(nominal_speed_sqr-pl_block->entry_speed_sqr);
741  }
742  } else {
743  prep.accelerate_until = intersect_distance;
744  prep.decelerate_after = intersect_distance;
745  prep.maximum_speed = sqrt(2.0*pl_block->acceleration*intersect_distance+exit_speed_sqr);
746  }
747  } else {
748  prep.ramp_type = RAMP_DECEL;
749 // prep.decelerate_after = pl_block->millimeters;
750 // prep.maximum_speed = prep.current_speed;
751  }
752  } else {
753  prep.accelerate_until = 0.0;
754  // prep.decelerate_after = 0.0;
755  prep.maximum_speed = prep.exit_speed;
756  }
757  }
758 
760  }
761 
762 // Initialize new segment
763  segment_t *prep_segment = &segment_buffer[segment_buffer_head];
764 
765 // Set new segment to point to the current segment data block.
766  prep_segment->st_block_index = prep.st_block_index;
767 
768  /*------------------------------------------------------------------------------------
769  Compute the average velocity of this new segment by determining the total distance
770  traveled over the segment time DT_SEGMENT. The following code first attempts to create
771  a full segment based on the current ramp conditions. If the segment time is incomplete
772  when terminating at a ramp state change, the code will continue to loop through the
773  progressing ramp states to fill the remaining segment execution time. However, if
774  an incomplete segment terminates at the end of the velocity profile, the segment is
775  considered completed despite having a truncated execution time less than DT_SEGMENT.
776  The velocity profile is always assumed to progress through the ramp sequence:
777  acceleration ramp, cruising state, and deceleration ramp. Each ramp's travel distance
778  may range from zero to the length of the block. Velocity profiles can end either at
779  the end of planner block (typical) or mid-block at the end of a forced deceleration,
780  such as from a feed hold.
781  */
782  float dt_max = DT_SEGMENT;
783  float dt = 0.0;
784  float time_var = dt_max;
785  float mm_var;
786  float speed_var;
787  float mm_remaining = pl_block->millimeters;
788  float minimum_mm = mm_remaining-prep.req_mm_increment;
789  if (minimum_mm < 0.0) { minimum_mm = 0.0; }
790 
791  do {
792  switch (prep.ramp_type) {
793  case RAMP_DECEL_OVERRIDE:
794  speed_var = pl_block->acceleration*time_var;
795  mm_var = time_var*(prep.current_speed - 0.5*speed_var);
796  mm_remaining -= mm_var;
797  if ((mm_remaining < prep.accelerate_until) || (mm_var <= 0)) {
798 // Cruise or cruise-deceleration types only for deceleration override.
799  mm_remaining = prep.accelerate_until;
800  time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
801  prep.ramp_type = RAMP_CRUISE;
802  prep.current_speed = prep.maximum_speed;
803  } else {
804  prep.current_speed -= speed_var;
805  }
806  break;
807  case RAMP_ACCEL:
808 // NOTE: Acceleration ramp only computes during first do-while loop.
809  speed_var = pl_block->acceleration*time_var;
810  mm_remaining -= time_var*(prep.current_speed + 0.5*speed_var);
811  if (mm_remaining < prep.accelerate_until) {
812 // Acceleration-cruise, acceleration-deceleration ramp junction, or end of block.
813  mm_remaining = prep.accelerate_until;
814  time_var = 2.0*(pl_block->millimeters-mm_remaining)/(prep.current_speed+prep.maximum_speed);
815  if (mm_remaining == prep.decelerate_after) { prep.ramp_type = RAMP_DECEL; }
816  else { prep.ramp_type = RAMP_CRUISE; }
817  prep.current_speed = prep.maximum_speed;
818  } else {
819  prep.current_speed += speed_var;
820  }
821  break;
822  case RAMP_CRUISE:
823 // NOTE: mm_var used to retain the last mm_remaining for incomplete segment time_var calculations.
824 // NOTE: If maximum_speed*time_var value is too low, round-off can cause mm_var to not change. To
825 // prevent this, simply enforce a minimum speed threshold in the planner.
826  mm_var = mm_remaining - prep.maximum_speed*time_var;
827  if (mm_var < prep.decelerate_after) {
828 // Cruise-deceleration junction or end of block.
829  time_var = (mm_remaining - prep.decelerate_after)/prep.maximum_speed;
830  mm_remaining = prep.decelerate_after;
831  prep.ramp_type = RAMP_DECEL;
832  } else {
833  mm_remaining = mm_var;
834  }
835  break;
836  default:
837 // NOTE: mm_var used as a misc worker variable to prevent errors when near zero speed.
838  speed_var = pl_block->acceleration*time_var;
839  if (prep.current_speed > speed_var) {
840 // Compute distance from end of segment to end of block.
841  mm_var = mm_remaining - time_var*(prep.current_speed - 0.5*speed_var);
842  if (mm_var > prep.mm_complete) {
843  mm_remaining = mm_var;
844  prep.current_speed -= speed_var;
845  break;
846  }
847  }
848 // Otherwise, at end of block or end of forced-deceleration.
849  time_var = 2.0*(mm_remaining-prep.mm_complete)/(prep.current_speed+prep.exit_speed);
850  mm_remaining = prep.mm_complete;
851  prep.current_speed = prep.exit_speed;
852  }
853  dt += time_var;
854  if (dt < dt_max) { time_var = dt_max - dt; }
855  else {
856  if (mm_remaining > minimum_mm) {
857 // Increase segment time to ensure at least one step in segment. Override and loop
858 // through distance calculations until minimum_mm or mm_complete.
859  dt_max += DT_SEGMENT;
860  time_var = dt_max - dt;
861  } else {
862  break;
863  }
864  }
865  } while (mm_remaining > prep.mm_complete);
866 
867 
868  /* -----------------------------------------------------------------------------------
869  Compute spindle speed PWM output for step segment
870  */
871 
874  float rpm = pl_block->spindle_speed;
875 // NOTE: Feed and rapid overrides are independent of PWM value and do not alter laser power/rate.
876  if (st_prep_block->is_pwm_rate_adjusted) { rpm *= (prep.current_speed * prep.inv_rate); }
877 // If current_speed is zero, then may need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE)
878 // but this would be instantaneous only and during a motion. May not matter at all.
880  } else {
881  sys.spindle_speed = 0.0;
882  prep.current_spindle_pwm = SPINDLE_PWM_OFF_VALUE;
883  }
885  }
886  prep_segment->spindle_pwm = prep.current_spindle_pwm;
887 
888 
889  /* -----------------------------------------------------------------------------------
890  Compute segment step rate, steps to execute, and apply necessary rate corrections.
891  \note Steps are computed by direct scalar conversion of the millimeter distance
892  remaining in the block, rather than incrementally tallying the steps executed per
893  segment. This helps in removing floating point round-off issues of several additions.
894  However, since floats have only 7.2 significant digits, long moves with extremely
895  high step counts can exceed the precision of floats, which can lead to lost steps.
896  Fortunately, this scenario is highly unlikely and unrealistic in CNC machines
897  supported by Grbl (i.e. exceeding 10 meters axis travel at 200 step/mm).
898  */
899  float step_dist_remaining = prep.step_per_mm*mm_remaining;
900  float n_steps_remaining = ceil(step_dist_remaining);
901  float last_n_steps_remaining = ceil(prep.steps_remaining);
902  prep_segment->n_step = last_n_steps_remaining-n_steps_remaining;
903 
904 // Bail if we are at the end of a feed hold and don't have a step to execute.
905  if (prep_segment->n_step == 0) {
907 // Less than one step to decelerate to zero speed, but already very close. AMASS
908 // requires full steps to execute. So, just bail.
910  #ifdef PARKING_ENABLE
912  #endif
913  return;
914  }
915  }
916 
917 // Compute segment step rate. Since steps are integers and mm distances traveled are not,
918 // the end of every segment can have a partial step of varying magnitudes that are not
919 // executed, because the stepper ISR requires whole steps due to the AMASS algorithm. To
920 // compensate, we track the time to execute the previous segment's partial step and simply
921 // apply it with the partial step distance to the current segment, so that it minutely
922 // adjusts the whole segment rate to keep step output exact. These rate adjustments are
923 // typically very small and do not adversely effect performance, but ensures that Grbl
924 // outputs the exact acceleration and velocity profiles as computed by the planner.
925  dt += prep.dt_remainder;
926  float inv_rate = dt/(last_n_steps_remaining - step_dist_remaining);
927 
928 // Compute CPU cycles per step for the prepped segment.
929  uint32_t cycles = ceil( (TICKS_PER_MICROSECOND*1000000*60)*inv_rate );
930 
931  #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
932 // Compute step timing and multi-axis smoothing level.
933 // NOTE: AMASS overdrives the timer with each level, so only one prescalar is required.
934  if (cycles < AMASS_LEVEL1) { prep_segment->amass_level = 0; }
935  else {
936  if (cycles < AMASS_LEVEL2) { prep_segment->amass_level = 1; }
937  else if (cycles < AMASS_LEVEL3) { prep_segment->amass_level = 2; }
938  else { prep_segment->amass_level = 3; }
939  cycles >>= prep_segment->amass_level;
940  prep_segment->n_step <<= prep_segment->amass_level;
941  }
942  if (cycles < (1UL << 16)) { prep_segment->cycles_per_tick = cycles; }
943  else { prep_segment->cycles_per_tick = 0xffff; }
944  #else
945 // Compute step timing and timer prescalar for normal step generation.
946  if (cycles < (1UL << 16)) {
947  prep_segment->prescaler = 1;
948  prep_segment->cycles_per_tick = cycles;
949  } else if (cycles < (1UL << 19)) {
950  prep_segment->prescaler = 2;
951  prep_segment->cycles_per_tick = cycles >> 3;
952  } else {
953  prep_segment->prescaler = 3;
954  if (cycles < (1UL << 22)) {
955  prep_segment->cycles_per_tick = cycles >> 6;
956  } else {
957  prep_segment->cycles_per_tick = 0xffff;
958  }
959  }
960  #endif
961 
962 // Segment complete! Increment segment buffer indices, so stepper ISR can immediately execute it.
963  segment_buffer_head = segment_next_head;
964  if ( ++segment_next_head == SEGMENT_BUFFER_SIZE ) { segment_next_head = 0; }
965 
966 // Update the appropriate planner and segment data.
967  pl_block->millimeters = mm_remaining;
968  prep.steps_remaining = n_steps_remaining;
969  prep.dt_remainder = (n_steps_remaining - step_dist_remaining)*inv_rate;
970 
971 // Check for exit conditions and flag to load next planner block.
972  if (mm_remaining == prep.mm_complete) {
973 // End of planner block or forced-termination. No more distance to be executed.
974  if (mm_remaining > 0.0) {
975 // Reset prep parameters for resuming and then bail. Allow the stepper ISR to complete
976 // the segment queue, where realtime protocol will set new state upon receiving the
977 // cycle stop flag from the ISR. Prep_segment is blocked until then.
979  #ifdef PARKING_ENABLE
981  #endif
982  return;
983  } else {
984 // The planner block is complete. All steps are set to be executed in the segment buffer.
987  return;
988  }
989  pl_block = NULL;
991  }
992  }
993 
994  }
995 }
996 
998 // however is not exactly the current speed, but the speed computed in the last step segment
999 // in the segment buffer. It will always be behind by up to the number of segment blocks (-1)
1000 // divided by the ACCELERATION TICKS PER SECOND in seconds.
1002 {
1004  return prep.current_speed;
1005  }
1006  return 0.0f;
1007 }
void st_parking_restore_buffer()
Restores the step segment buffer to the normal run state after a parking motion.
uint8_t dir_outbits
Definition: stepper.c:99
#define BITFLAG_INVERT_ST_ENABLE
Definition: settings.h:37
#define AMASS_LEVEL1
Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz)
Definition: stepper.c:51
volatile uint8_t sys_probe_state
Probing state value. Used to coordinate the probing cycle with stepper ISR.
Definition: system.h:133
float accelerate_until
Acceleration ramp end measured from end of block (mm)
Definition: stepper.c:147
float exit_speed
Exit speed of executing block (mm/min)
Definition: stepper.c:146
plan_block_t * plan_get_current_block()
Returns address of first planner block, if available. Called by various main program functions...
Definition: planner.c:231
#define RAMP_ACCEL
Definition: stepper.c:27
void st_parking_setup_buffer()
Changes the run state of the step segment buffer to execute the special parking motion.
if(axis_words)
STEP 3: Error-check all commands and values passed in this block. This step ensures all of the comma...
Definition: gcode.c:367
float programmed_rate
Programmed rate of this block (mm/min).
Definition: planner.h:71
void probe_state_monitor()
Monitors probe pin state and records the system position when detected. Called by the...
Definition: probe.c:55
#define N_AXIS
Axis array index values. Must start with 0 and be continuous.
Definition: nuts_bolts.h:30
#define SEGMENT_BUFFER_SIZE
Definition: stepper.h:26
float mm_complete
End of velocity profile from end of current planner block in (mm).
Definition: stepper.c:142
Primary stepper segment ring buffer. Contains small, short line segments for the stepper.
Definition: stepper.c:73
#define STATE_HOLD
Active feed hold.
Definition: system.h:77
#define Y_AXIS
Definition: nuts_bolts.h:32
uint16_t current_spindle_pwm
Definition: stepper.c:151
uint16_t spindle_compute_pwm_value(float rpm)
Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
#define bit_true(x, mask)
Definition: nuts_bolts.h:58
#define STEP_CONTROL_UPDATE_SPINDLE_PWM
Definition: system.h:96
#define RAMP_DECEL_OVERRIDE
Definition: stepper.c:30
uint8_t st_block_index
Index of stepper common data block being prepped.
Definition: stepper.c:126
uint32_t steps[N_AXIS]
Definition: stepper.c:62
uint8_t direction_bits
The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
Definition: planner.h:52
void system_set_exec_state_flag(uint8_t mask)
Special handlers for setting and clearing Grbl's real-time execution flags.
Definition: system.c:340
Stores the planner block Bresenham algorithm execution data for the segments in the segment...
Definition: stepper.c:61
uint32_t step_event_count
Definition: stepper.c:63
#define EXEC_CYCLE_STOP
bitmask 00000100
Definition: system.h:33
#define PROBE_ACTIVE
Actively watching the input pin.
Definition: probe.h:25
uint8_t recalculate_flag
Definition: stepper.c:127
#define PREP_FLAG_RECALCULATE
Definition: stepper.c:32
float plan_compute_profile_nominal_speed(plan_block_t *block)
Computes and returns block nominal speed based on running condition and override values.
Definition: planner.c:255
float current_speed
Current speed at the end of the segment buffer (mm/min)
Definition: stepper.c:144
void stepper_init()
Initialize and start the stepper motor subsystem.
Definition: stepper.c:500
uint32_t counter_x
Counter variables for the bresenham line tracer.
Definition: stepper.c:89
uint16_t cycles_per_tick
Step distance traveled per ISR tick, aka step rate.
Definition: stepper.c:75
uint8_t st_block_index
Stepper block data index. Uses this information to execute this segment.
Definition: stepper.c:76
float dt_remainder
Definition: stepper.c:129
#define PL_COND_FLAG_SPINDLE_CW
Definition: planner.h:37
volatile uint8_t sys_rt_exec_alarm
Global realtime executor bitflag variable for setting various alarms.
Definition: system.h:135
segment_t * exec_segment
Pointer to the segment being executed.
Definition: stepper.c:107
float st_get_realtime_rate()
Called by realtime status reporting to fetch the current speed being executed. This value...
Definition: stepper.c:1001
uint8_t condition
Block bitflag variable defining block run conditions. Copied from pl_line_data.
Definition: planner.h:55
#define PREP_FLAG_DECEL_OVERRIDE
Definition: stepper.c:35
uint8_t execute_step
Flags step execution for each interrupt.
Definition: stepper.c:96
uint8_t state
Tracks the current system state of Grbl.
Definition: system.h:112
float plan_get_exec_block_exit_speed_sqr()
Called by step segment buffer when computing executing block velocity profile.
Definition: planner.c:238
#define STEP_CONTROL_EXECUTE_HOLD
Definition: system.h:94
float entry_speed_sqr
The current planned entry speed at block junction in (mm/min)^2.
Definition: planner.h:60
float millimeters
The remaining distance for this block to be executed in (mm).
Definition: planner.h:64
#define BITFLAG_LASER_MODE
Definition: settings.h:36
Stepper ISR data struct. Contains the running data for the main stepper ISR.
Definition: stepper.c:87
float acceleration
Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
Definition: planner.h:63
Segment preparation data struct. Contains all the necessary information to compute new segments...
Definition: stepper.c:125
uint8_t get_direction_pin_mask(uint8_t axis_idx)
Returns direction pin mask according to Grbl internal axis indexing.
Definition: settings.c:316
uint8_t direction_bits
Definition: stepper.c:64
#define X_AXIS
Axis indexing value.
Definition: nuts_bolts.h:31
float spindle_speed
Block spindle speed. Copied from pl_line_data.
Definition: planner.h:74
#define bit(n)
Bit field and masking macros.
Definition: nuts_bolts.h:57
plan_block_t * plan_get_system_motion_block()
Returns address of planner buffer block used by system motions. Called by segment generator...
Definition: planner.c:225
#define STATE_SLEEP
Sleep state.
Definition: system.h:80
#define Z_AXIS
Definition: nuts_bolts.h:33
#define STATE_CYCLE
Cycle is running or motions are being executed.
Definition: system.h:76
#define RAMP_CRUISE
Definition: stepper.c:28
uint8_t flags
Contains default boolean settings.
Definition: settings.h:92
uint32_t counter_y
Definition: stepper.c:89
uint8_t step_invert_mask
Definition: settings.h:82
#define AMASS_LEVEL2
Over-drives ISR (x4)
Definition: stepper.c:52
#define DT_SEGMENT
Some useful constants.
Definition: stepper.c:25
uint8_t exec_block_index
Tracks the current st_block index. Change indicates new block.
Definition: stepper.c:105
uint16_t spindle_pwm
Definition: stepper.c:82
system_t sys
Declare system global variable structure.
Definition: main.c:25
float steps_remaining
Definition: stepper.c:130
int32_t sys_position[N_AXIS]
NOTE: These position variables may need to be declared as volatiles, if problems arise.
Definition: system.h:130
uint8_t dir_invert_mask
Definition: settings.h:83
void spindle_set_speed(uint16_t pwm_value)
Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state() ...
void st_go_idle()
Stepper shutdown.
Definition: stepper.c:224
ISR(TIMER1_COMPA_vect)
"The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl.
Definition: stepper.c:304
uint8_t step_control
Governs the step segment generator depending on system state.
Definition: system.h:116
void st_prep_buffer()
Prepares step segment buffer. Continuously called from main program.
Definition: stepper.c:594
#define PREP_FLAG_PARKING
Definition: stepper.c:34
void plan_discard_current_block()
Called when the current block is no longer needed. Discards the block and makes the memory...
Definition: planner.c:214
void st_wake_up()
BLOCK VELOCITY PROFILE DEFINITION.
Definition: stepper.c:199
uint8_t get_step_pin_mask(uint8_t axis_idx)
Returns step pin mask according to Grbl internal axis indexing.
Definition: settings.c:308
float inv_rate
Used by PWM laser mode to speed up segment calculations.
Definition: stepper.c:150
uint32_t step_event_count
The maximum step axis count and number of steps required to complete this block.
Definition: planner.h:51
#define PREP_FLAG_HOLD_PARTIAL_BLOCK
Definition: stepper.c:33
#define STEP_PORT_SET(i)
The cpu_map.h files serve as a central pin mapping selection file for different processor types or al...
Definition: cpu_map.h:148
memset(pl_data, 0, sizeof(plan_line_data_t))
Zero pl_data struct.
uint8_t homing_axis_lock
Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
Definition: system.h:118
float decelerate_after
Deceleration ramp start measured from end of block (mm)
Definition: stepper.c:148
float step_per_mm
Definition: stepper.c:131
settings_t settings
Definition: settings.c:24
#define MAX_AMASS_LEVEL
Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level...
Definition: stepper.c:49
uint8_t pulse_microseconds
Definition: settings.h:81
#define DIRECTION_PORT_SET(i)
Definition: cpu_map.h:149
uint8_t ramp_type
Current segment ramp state.
Definition: stepper.c:141
#define AMASS_LEVEL3
Over-drives ISR (x8)
Definition: stepper.c:53
float spindle_speed
Definition: system.h:125
uint8_t step_pulse_time
Step pulse reset time after step rise.
Definition: stepper.c:97
#define bit_false(x, mask)
Definition: nuts_bolts.h:59
uint32_t counter_z
Definition: stepper.c:89
float req_mm_increment
Definition: stepper.c:132
#define STEP_CONTROL_END_MOTION
Definition: system.h:93
uint16_t step_count
Steps remaining in line segment motion.
Definition: stepper.c:104
float maximum_speed
Maximum speed of executing block. Not always nominal speed. (mm/min)
Definition: stepper.c:145
#define STATE_JOG
Jogging mode.
Definition: system.h:78
#define STATE_HOMING
Performing homing cycle.
Definition: system.h:75
uint16_t n_step
Number of step events to be executed for this segment.
Definition: stepper.c:74
st_block_t * exec_block
Pointer to the block data for the segment being executed.
Definition: stepper.c:106
uint8_t step_outbits
The next stepping-bits to be output.
Definition: stepper.c:98
This struct stores a linear movement of a g-code block motion with its critical "nominal" values...
Definition: planner.h:46
uint32_t steps[N_AXIS]
Definition: stepper.c:101
#define RAMP_DECEL
Definition: stepper.c:29
void st_update_plan_block_parameters()
Called by planner_recalculate() when the executing block is updated by the new plan.
Definition: stepper.c:526
#define STEP_CONTROL_EXECUTE_SYS_MOTION
Definition: system.h:95
void delay_ms(uint16_t ms)
Delays variable defined milliseconds. Compiler compatibility fix for _delay_ms(),.
Definition: nuts_bolts.c:129
uint32_t steps[N_AXIS]
NOTE: Used by stepper algorithm to execute the block correctly. Do not alter these values...
Definition: planner.h:50
#define PL_COND_FLAG_SPINDLE_CCW
Definition: planner.h:38
uint8_t is_pwm_rate_adjusted
Tracks motions that require constant laser power/rate.
Definition: stepper.c:65
void st_generate_step_dir_invert_masks()
Generates the step and direction port invert masks used in the Stepper Interrupt Driver.
Definition: stepper.c:464
uint8_t amass_level
Indicates AMASS level for the ISR to execute this segment.
Definition: stepper.c:78
#define TICKS_PER_MICROSECOND
Definition: nuts_bolts.h:45
void st_reset()
Reset and clear stepper subsystem variables.
Definition: stepper.c:476
uint8_t stepper_idle_lock_time
If max value 255, steppers do not disable.
Definition: settings.h:84
#define REQ_MM_INCREMENT_SCALAR
Definition: stepper.c:26
#define bit_istrue(x, mask)
Definition: nuts_bolts.h:60
#define STATE_SAFETY_DOOR
Safety door is ajar. Feed holds and de-energizes system.
Definition: system.h:79