gnea\grbl-Mega  1.0f
Source Code Documentation ( Internal Workings )
stepper.c File Reference
#include "grbl.h"

Go to the source code of this file.

Data Structures

struct  st_block_t
 Stores the planner block Bresenham algorithm execution data for the segments in the segment. More...
 
struct  segment_t
 Primary stepper segment ring buffer. Contains small, short line segments for the stepper. More...
 
struct  stepper_t
 Stepper ISR data struct. Contains the running data for the main stepper ISR. More...
 
struct  st_prep_t
 Segment preparation data struct. Contains all the necessary information to compute new segments. More...
 

Macros

#define DT_SEGMENT   (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0))
 Some useful constants. More...
 
#define REQ_MM_INCREMENT_SCALAR   1.25
 
#define RAMP_ACCEL   0
 
#define RAMP_CRUISE   1
 
#define RAMP_DECEL   2
 
#define RAMP_DECEL_OVERRIDE   3
 
#define PREP_FLAG_RECALCULATE   bit(0)
 
#define PREP_FLAG_HOLD_PARTIAL_BLOCK   bit(1)
 
#define PREP_FLAG_PARKING   bit(2)
 
#define PREP_FLAG_DECEL_OVERRIDE   bit(3)
 
#define MAX_AMASS_LEVEL   3
 Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level. More...
 
#define AMASS_LEVEL1   (F_CPU/8000)
 Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz) More...
 
#define AMASS_LEVEL2   (F_CPU/4000)
 Over-drives ISR (x4) More...
 
#define AMASS_LEVEL3   (F_CPU/2000)
 Over-drives ISR (x8) More...
 

Functions

void st_wake_up ()
 BLOCK VELOCITY PROFILE DEFINITION. More...
 
void st_go_idle ()
 Stepper shutdown. More...
 
 ISR (TIMER1_COMPA_vect)
 "The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. More...
 
 ISR (TIMER0_OVF_vect)
 The Stepper Port Reset Interrupt: Timer0 OVF interrupt handles the falling edge of the step pulse. This should always trigger before the next Timer1 COMPA interrupt and independently finish, if Timer1 is disabled after completing a move. More...
 
void st_generate_step_dir_invert_masks ()
 Generates the step and direction port invert masks used in the Stepper Interrupt Driver. More...
 
void st_reset ()
 Reset and clear stepper subsystem variables. More...
 
void stepper_init ()
 Initialize and start the stepper motor subsystem. More...
 
void st_update_plan_block_parameters ()
 Called by planner_recalculate() when the executing block is updated by the new plan. More...
 
void st_prep_buffer ()
 Prepares step segment buffer. Continuously called from main program. More...
 
float st_get_realtime_rate ()
 Called by realtime status reporting to fetch the current speed being executed. This value. More...
 

Data Structure Documentation

struct st_block_t

Stores the planner block Bresenham algorithm execution data for the segments in the segment.

Definition at line 61 of file stepper.c.

Data Fields
uint8_t direction_bits
uint8_t is_pwm_rate_adjusted Tracks motions that require constant laser power/rate.
uint32_t step_event_count
uint32_t steps[N_AXIS]
struct segment_t

Primary stepper segment ring buffer. Contains small, short line segments for the stepper.

Definition at line 73 of file stepper.c.

Data Fields
uint8_t amass_level Indicates AMASS level for the ISR to execute this segment.
uint16_t cycles_per_tick Step distance traveled per ISR tick, aka step rate.
uint16_t n_step Number of step events to be executed for this segment.
uint16_t spindle_pwm
uint8_t st_block_index Stepper block data index. Uses this information to execute this segment.
struct stepper_t

Stepper ISR data struct. Contains the running data for the main stepper ISR.

Definition at line 87 of file stepper.c.

Data Fields
uint32_t counter_x Counter variables for the bresenham line tracer.
uint32_t counter_y
uint32_t counter_z
uint8_t dir_outbits
st_block_t * exec_block Pointer to the block data for the segment being executed.
uint8_t exec_block_index Tracks the current st_block index. Change indicates new block.
segment_t * exec_segment Pointer to the segment being executed.
uint8_t execute_step Flags step execution for each interrupt.
uint16_t step_count Steps remaining in line segment motion.
uint8_t step_outbits The next stepping-bits to be output.
uint8_t step_pulse_time Step pulse reset time after step rise.
uint32_t steps[N_AXIS]
struct st_prep_t

Segment preparation data struct. Contains all the necessary information to compute new segments.

Definition at line 125 of file stepper.c.

Data Fields
float accelerate_until Acceleration ramp end measured from end of block (mm)
float current_speed Current speed at the end of the segment buffer (mm/min)
uint16_t current_spindle_pwm
float decelerate_after Deceleration ramp start measured from end of block (mm)
float dt_remainder
float exit_speed Exit speed of executing block (mm/min)
float inv_rate Used by PWM laser mode to speed up segment calculations.
float maximum_speed Maximum speed of executing block. Not always nominal speed. (mm/min)
float mm_complete End of velocity profile from end of current planner block in (mm).
uint8_t ramp_type Current segment ramp state.
uint8_t recalculate_flag
float req_mm_increment
uint8_t st_block_index Index of stepper common data block being prepped.
float step_per_mm
float steps_remaining

Macro Definition Documentation

#define AMASS_LEVEL1   (F_CPU/8000)

Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz)

Definition at line 51 of file stepper.c.

#define AMASS_LEVEL2   (F_CPU/4000)

Over-drives ISR (x4)

Definition at line 52 of file stepper.c.

#define AMASS_LEVEL3   (F_CPU/2000)

Over-drives ISR (x8)

Definition at line 53 of file stepper.c.

#define DT_SEGMENT   (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0))

Some useful constants.

min/segment

Definition at line 25 of file stepper.c.

#define MAX_AMASS_LEVEL   3

Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level.

frequency bin starts at 0Hz and ends at its cutoff frequency. The next lower level frequency bin starts at the next higher cutoff frequency, and so on. The cutoff frequencies for each level must be considered carefully against how much it over-drives the stepper ISR, the accuracy of the 16-bit timer, and the CPU overhead. Level 0 (no AMASS, normal operation) frequency bin starts at the Level 1 cutoff frequency and up to as fast as the CPU allows (over 30kHz in limited testing).

Note
AMASS cutoff frequency multiplied by ISR overdrive factor must not exceed maximum step frequency.
Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead and timer accuracy. Do not alter these settings unless you know what you are doing.

Definition at line 49 of file stepper.c.

#define PREP_FLAG_DECEL_OVERRIDE   bit(3)

Definition at line 35 of file stepper.c.

#define PREP_FLAG_HOLD_PARTIAL_BLOCK   bit(1)

Definition at line 33 of file stepper.c.

#define PREP_FLAG_PARKING   bit(2)

Definition at line 34 of file stepper.c.

#define PREP_FLAG_RECALCULATE   bit(0)

Definition at line 32 of file stepper.c.

#define RAMP_ACCEL   0

Definition at line 27 of file stepper.c.

#define RAMP_CRUISE   1

Definition at line 28 of file stepper.c.

#define RAMP_DECEL   2

Definition at line 29 of file stepper.c.

#define RAMP_DECEL_OVERRIDE   3

Definition at line 30 of file stepper.c.

#define REQ_MM_INCREMENT_SCALAR   1.25

Definition at line 26 of file stepper.c.

Function Documentation

ISR ( TIMER1_COMPA_vect  )

"The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl.

Grbl employs the venerable Bresenham line algorithm to manage and exactly synchronize multi-axis moves. Unlike the popular DDA algorithm, the Bresenham algorithm is not susceptible to numerical round-off errors and only requires fast integer counters, meaning low computational overhead and maximizing the Arduino's capabilities.

However, the downside of the Bresenham algorithm is, for certain multi-axis motions, the non-dominant axes may suffer from un-smooth step pulse trains, or aliasing, which can lead to strange audible noises or shaking. This is particularly noticeable or may cause motion issues at low step frequencies (0-5kHz), but is usually not a physical problem at higher frequencies, although audible.

To improve Bresenham multi-axis performance, Grbl uses what we call an Adaptive Multi-Axis Step Smoothing (AMASS) algorithm, which does what the name implies. At lower step frequencies, AMASS artificially increases the Bresenham resolution without effecting the algorithm's innate exactness. AMASS adapts its resolution levels automatically depending on the step frequency to be executed, meaning that for even lower step frequencies the step smoothing level increases. Algorithmically, AMASS is acheived by a simple bit-shifting of the Bresenham step count for each AMASS level.

For example, for a Level 1 step smoothing, we bit shift the Bresenham step event count, effectively multiplying it by 2, while the axis step counts remain the same, and then double the stepper ISR frequency. In effect, we are allowing the non-dominant Bresenham axes step in the intermediate ISR tick, while the dominant axis is stepping every two ISR ticks, rather than every ISR tick in the traditional sense.

At AMASS Level 2, we simply bit-shift again, so the non-dominant Bresenham axes can step within any of the four ISR ticks, the dominant axis steps every four ISR ticks, and quadruple the stepper ISR frequency. And so on. This, in effect, virtually eliminates multi-axis aliasing issues with the Bresenham algorithm and does not significantly alter Grbl's performance, but in fact, more efficiently utilizes unused CPU cycles overall throughout all configurations.

AMASS retains the Bresenham algorithm exactness by requiring that it always executes a full Bresenham step, regardless of AMASS Level. Meaning that for an AMASS Level 2, all four intermediate steps must be completed such that baseline Bresenham (Level 0) count is always retained. Similarly, AMASS Level 3 means all eight intermediate steps must be executed. Although the AMASS Levels are in reality arbitrary, where the baseline Bresenham counts can be multiplied by any integer value, multiplication by powers of two are simply used to ease CPU overhead with bitshift integer operations.

This interrupt is simple and dumb by design. All the computational heavy-lifting, as in determining accelerations, is performed elsewhere. This interrupt pops pre-computed segments, defined as constant velocity over n number of steps, from the step segment buffer and then executes them by pulsing the stepper pins appropriately via the Bresenham algorithm. This ISR is supported by The Stepper Port Reset Interrupt which it uses to reset the stepper port after each pulse. The bresenham line tracer algorithm controls all stepper outputs simultaneously with these two interrupts.

Note
This interrupt must be as efficient as possible and complete before the next ISR tick, which for Grbl must be less than 33.3usec (@30kHz ISR rate). Oscilloscope measured time in ISR is 5usec typical and 25usec maximum, well below requirement.
This ISR expects at least one step to be executed per segment.
Todo:
Replace direct updating of the int32 position counters in the ISR somehow. Perhaps use smaller int8 variables and update position counters only when a segment completes. This can get complicated with probing and homing cycles that require true real-time positions.

<

Note
Can sometimes be zero when moving slow.

< Flag main program for cycle end

< Nothing to do but exit.

< Decrement step events count

< Apply step port invert mask

Definition at line 304 of file stepper.c.

ISR ( TIMER0_OVF_vect  )

The Stepper Port Reset Interrupt: Timer0 OVF interrupt handles the falling edge of the step pulse. This should always trigger before the next Timer1 COMPA interrupt and independently finish, if Timer1 is disabled after completing a move.

Note
Interrupt collisions between the serial and stepper interrupts can cause delays by a few microseconds, if they execute right before one another. Not a big deal, but can cause issues at high step rates if another high frequency asynchronous interrupt is added to Grbl.
This interrupt is enabled by ISR_TIMER1_COMPAREA when it sets the motor port bits to execute a step. This ISR resets the motor port after a short period (settings.pulse_microseconds) completing one step cycle.

< Disable Timer0 to prevent re-entering this interrupt when it's not needed.

Definition at line 444 of file stepper.c.

void st_generate_step_dir_invert_masks ( )

Generates the step and direction port invert masks used in the Stepper Interrupt Driver.

Generate the step and direction port invert masks.

Definition at line 464 of file stepper.c.

float st_get_realtime_rate ( )

Called by realtime status reporting to fetch the current speed being executed. This value.

Called by realtime status reporting if realtime rate reporting is enabled in config.h.

Definition at line 1001 of file stepper.c.

void st_go_idle ( )

Stepper shutdown.

Immediately disables steppers.

< Disable Timer1 interrupt

< Reset clock to no prescaling.

< Keep enabled.

< Override. Disable steppers.

Definition at line 224 of file stepper.c.

void st_prep_buffer ( )

Prepares step segment buffer. Continuously called from main program.

Reloads step segment buffer. Called continuously by realtime execution system.

The segment buffer is an intermediary buffer interface between the execution of steps by the stepper algorithm and the velocity profiles generated by the planner. The stepper algorithm only executes steps within the segment buffer and is filled by the main program when steps are "checked-out" from the first block in the planner buffer. This keeps the step execution and planning optimization processes atomic and protected from each other. The number of steps "checked-out" from the planner buffer and the number of segments in the segment buffer is sized and computed such that no operation in the main program takes longer than the time it takes the stepper algorithm to empty it before refilling it. Currently, the segment buffer conservatively holds roughly up to 40-50 msec of steps.

Note
Computation units are in steps, millimeters, and minutes.

< Check if we need to fill the buffer.

< Reset for new segment block

< Default velocity profile complete at 0.0mm from end of block.

< [Forced Deceleration to Zero Velocity]

< End of feed hold.

< [Normal Operation]

< Initialize as acceleration ramp.

< Enforce stop at end of system motion.

< Only occurs during override reductions.

< Deceleration-only.

< Flag to load next block as deceleration override.

Todo:
Determine correct handling of parameters in deceleration-only.

< Either trapezoid or triangle types

< Trapezoid type

< Triangle type

< Deceleration-only type

< Acceleration-only type

< Force update whenever updating block.

< Maximum segment time

< Initialize segment time

< Time worker variable

< mm-Distance worker variable

< Speed worker variable

< New segment distance from end of block.

< Guarantee at least one step.

<

Note
0.0 at EOB

< Mid-deceleration override ramp.

< End of acceleration ramp.

<

Note
0.0 at EOB

< Acceleration only.

< End of cruise.

<

Note
0.0 at EOB

< Cruising only.

< case RAMP_DECEL:

< Used as delta speed (mm/min)

< Check if at or below zero speed.

< (mm)

< Typical case. In deceleration ramp.

< Segment complete. Exit switch-case statement. Continue do-while loop.

< Add computed ramp time to total segment time.

< Check for very slow segments with zero steps.

< Complete Exit loop. Segment execution time maxed.

< Complete Exit loop. Profile complete.

< Reload segment PWM value

< Convert mm_remaining to steps

< Round-up current steps remaining

< Round-up last steps remaining

< Compute number of steps to execute.

< Segment not generated, but current step data still retained.

< Apply previous segment partial step execute time

< Compute adjusted step rate inverse

< (cycles/step)

< At end of forced-termination.

< Bail!

< End of planner block

< Set pointer to indicate check and load next planner block.

Definition at line 594 of file stepper.c.

void st_reset ( )

Reset and clear stepper subsystem variables.

Reset the stepper subsystem variables.

< Planner block pointer used by segment buffer

< empty = tail

< Initialize direction bits to default.

Definition at line 476 of file stepper.c.

void st_update_plan_block_parameters ( )

Called by planner_recalculate() when the executing block is updated by the new plan.

< Ignore if at start of a new block.

< Update entry speed.

< Flag st_prep_segment() to load and check active velocity profile.

Definition at line 526 of file stepper.c.

void st_wake_up ( )

BLOCK VELOCITY PROFILE DEFINITION.

Enable steppers, but cycle does not start unless called by motion control or realtime command.

          __________________________
         /|                        |\     _________________         ^
        / |                        | \   /|               |\        |
       /  |                        |  \ / |               | \       s
      /   |                        |   |  |               |  \      p
     /    |                        |   |  |               |   \     e
    +-----+------------------------+---+--+---------------+----+    e
    |               BLOCK 1            ^      BLOCK 2          |    d
                                       |
                  time ----->      EXAMPLE: Block 2 entry speed is at max junction velocity

The planner block buffer is planned assuming constant acceleration velocity profiles and are continuously joined at block junctions as shown above. However, the planner only actively computes the block entry speeds for an optimal velocity plan, but does not compute the block internal velocity profiles. These velocity profiles are computed ad-hoc as they are executed by the stepper algorithm and consists of only 7 possible types of profiles: cruise-only, cruise- deceleration, acceleration-cruise, acceleration-only, deceleration-only, full-trapezoid, and triangle(no cruise).

                                        maximum_speed (< nominal_speed) ->  +
                    +--------+ <- maximum_speed (= nominal_speed)          /|\
                   /          \                                           / | \
 current_speed -> +            \                                         /  |  + <- exit_speed
                  |             + <- exit_speed                         /   |  |
                  +-------------+                     current_speed -> +----+--+
                   time -->  ^  ^                                           ^  ^
                             |  |                                           |  |
                decelerate_after(in mm)                             decelerate_after(in mm)
                    ^           ^                                           ^  ^
                    |           |                                           |  |
                accelerate_until(in mm)                             accelerate_until(in mm)

The step segment buffer computes the executing block velocity profile and tracks the critical parameters for the stepper algorithm to accurately trace the profile. These critical parameters are shown and defined in the above illustration.Stepper state initialization. Cycle should only start if the st.cycle_start flag is

< Normal operation

Definition at line 199 of file stepper.c.

void stepper_init ( )

Initialize and start the stepper motor subsystem.

Initialize and setup the stepper motor subsystem.

< waveform generation = 0100 = CTC

< Disconnect OC1 output

< Disconnect OC0 outputs and OVF interrupt.

< Normal operation

< Disable Timer0 until needed

< Enable Timer0 overflow interrupt

Definition at line 500 of file stepper.c.