Skip to content

Instantly share code, notes, and snippets.

@Lloydy
Forked from nullsub/config.h
Created November 25, 2012 22:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lloydy/4145610 to your computer and use it in GitHub Desktop.
Save Lloydy/4145610 to your computer and use it in GitHub Desktop.
stepper.c file
/*
config.h - compile time configuration
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef config_h
#define config_h
// IMPORTANT: Any changes here requires a full re-compiling of the source code to propagate them.
#define BAUD_RATE 9600
// Updated default pin-assignments from 0.6 onwards
// (see bottom of file for a copy of the old config)
#define STEPPERS_DISABLE_DDR DDRB
#define STEPPERS_DISABLE_PORT PORTB
#define STEPPERS_DISABLE_BIT 0
//#define STEPPING_DDR DDRD
//#define STEPPING_PORT PORTD
#define X_STEP_BIT 2
#define Y_STEP_BIT 3
#define Z_STEP_BIT 4
#define X_DIRECTION_BIT 5
#define Y_DIRECTION_BIT 6
#define Z_DIRECTION_BIT 7
#define LIMIT_DDR DDRB
#define LIMIT_PIN PINB
#define X_LIMIT_BIT 1
#define Y_LIMIT_BIT 2
#define Z_LIMIT_BIT 3
#define SPINDLE_ENABLE_DDR DDRB
#define SPINDLE_ENABLE_PORT PORTB
#define SPINDLE_ENABLE_BIT 4
#define SPINDLE_DIRECTION_DDR DDRB
#define SPINDLE_DIRECTION_PORT PORTB
#define SPINDLE_DIRECTION_BIT 5
// This parameter sets the delay time before disabling the steppers after the final block of movement.
// A short delay ensures the steppers come to a complete stop and the residual inertial force in the
// CNC axes don't cause the axes to drift off position. This is particularly important when manually
// entering g-code into grbl, i.e. locating part zero or simple manual machining. If the axes drift,
// grbl has no way to know this has happened, since stepper motors are open-loop control. Depending
// on the machine, this parameter may need to be larger or smaller than the default time.
// NOTE: If defined 0, the delay will not be compiled.
#define STEPPER_IDLE_LOCK_TIME 25 // (milliseconds) - Integer >= 0
// The temporal resolution of the acceleration management subsystem. Higher number give smoother
// acceleration but may impact performance.
// NOTE: Increasing this parameter will help any resolution related issues, especially with machines
// requiring very high accelerations and/or very fast feedrates. In general, this will reduce the
// error between how the planner plans the motions and how the stepper program actually performs them.
// However, at some point, the resolution can be high enough, where the errors related to numerical
// round-off can be great enough to cause problems and/or it's too fast for the Arduino. The correct
// value for this parameter is machine dependent, so it's advised to set this only as high as needed.
// Approximate successful values can range from 30L to 100L or more.
#define ACCELERATION_TICKS_PER_SECOND 50L
// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end
// of the buffer and all stops. This should not be much greater than zero and should only be changed
// if unwanted behavior is observed on a user's machine when running at very slow speeds.
#define MINIMUM_PLANNER_SPEED 0.0 // (mm/min)
// Minimum stepper rate. Sets the absolute minimum stepper rate in the stepper program and never runs
// slower than this value, except when sleeping. This parameter overrides the minimum planner speed.
// This is primarily used to guarantee that the end of a movement is always reached and not stop to
// never reach its target. This parameter should always be greater than zero.
#define MINIMUM_STEPS_PER_MINUTE 800 // (steps/min) - Integer value only
// Number of arc generation iterations by small angle approximation before exact arc trajectory
// correction. This parameter maybe decreased if there are issues with the accuracy of the arc
// generations. In general, the default value is more than enough for the intended CNC applications
// of grbl, and should be on the order or greater than the size of the buffer to help with the
// computational efficiency of generating arcs.
#define N_ARC_CORRECTION 25 // Integer (1-255)
#endif
// Pin-assignments from Grbl 0.5
// #define STEPPERS_DISABLE_DDR DDRD
// #define STEPPERS_DISABLE_PORT PORTD
// #define STEPPERS_DISABLE_BIT 2
//
// #define STEPPING_DDR DDRC
// #define STEPPING_PORT PORTC
// #define X_STEP_BIT 0
// #define Y_STEP_BIT 1
// #define Z_STEP_BIT 2
// #define X_DIRECTION_BIT 3
// #define Y_DIRECTION_BIT 4
// #define Z_DIRECTION_BIT 5
//
// #define LIMIT_DDR DDRD
// #define LIMIT_PORT PORTD
// #define X_LIMIT_BIT 3
// #define Y_LIMIT_BIT 4
// #define Z_LIMIT_BIT 5
//
// #define SPINDLE_ENABLE_DDR DDRD
// #define SPINDLE_ENABLE_PORT PORTD
// #define SPINDLE_ENABLE_BIT 6
//
// #define SPINDLE_DIRECTION_DDR DDRD
// #define SPINDLE_DIRECTION_PORT PORTD
// #define SPINDLE_DIRECTION_BIT 7
/*
limits.h - code pertaining to limit-switches and performing the homing cycle
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include <util/delay.h>
#include <avr/io.h>
#include "stepper.h"
#include "settings.h"
#include "nuts_bolts.h"
#include "config.h"
void limits_init() {
//LIMIT_DDR &= ~(LIMIT_MASK);
}
static void homing_cycle(bool x_axis, bool y_axis, bool z_axis, bool reverse_direction, uint32_t microseconds_per_pulse) {
// First home the Z axis
/* NOT SUPPORTED
* uint32_t step_delay = microseconds_per_pulse - settings.pulse_microseconds;
uint8_t out_bits = DIRECTION_MASK;
uint8_t limit_bits;
if (x_axis) { out_bits |= (1<<X_STEP_BIT); }
if (y_axis) { out_bits |= (1<<Y_STEP_BIT); }
if (z_axis) { out_bits |= (1<<Z_STEP_BIT); }
// Invert direction bits if this is a reverse homing_cycle
if (reverse_direction) {
out_bits ^= DIRECTION_MASK;
}
// Apply the global invert mask
out_bits ^= settings.invert_mask;
// Set direction pins
STEPPING_PORT = (STEPPING_PORT & ~DIRECTION_MASK) | (out_bits & DIRECTION_MASK);
for(;;) {
limit_bits = LIMIT_PIN;
if (reverse_direction) {
// Invert limit_bits if this is a reverse homing_cycle
limit_bits ^= LIMIT_MASK;
}
if (x_axis && !(LIMIT_PIN & (1<<X_LIMIT_BIT))) {
x_axis = false;
out_bits ^= (1<<X_STEP_BIT);
}
if (y_axis && !(LIMIT_PIN & (1<<Y_LIMIT_BIT))) {
y_axis = false;
out_bits ^= (1<<Y_STEP_BIT);
}
if (z_axis && !(LIMIT_PIN & (1<<Z_LIMIT_BIT))) {
z_axis = false;
out_bits ^= (1<<Z_STEP_BIT);
}
// Check if we are done
if(!(x_axis || y_axis || z_axis)) { return; }
STEPPING_PORT |= out_bits & STEP_MASK;
delay_us(settings.pulse_microseconds);
STEPPING_PORT ^= out_bits & STEP_MASK;
delay_us(step_delay);
}*/
return;
}
static void approach_limit_switch(bool x, bool y, bool z) {
homing_cycle(x, y, z, false, 100000);
}
static void leave_limit_switch(bool x, bool y, bool z) {
homing_cycle(x, y, z, true, 500000);
}
void limits_go_home() {
st_synchronize();
// Store the current limit switch state
uint8_t original_limit_state = LIMIT_PIN;
approach_limit_switch(false, false, true); // First home the z axis
approach_limit_switch(true, true, false); // Then home the x and y axis
// Xor previous and current limit switch state to determine which were high then but have become
// low now. These are the actual installed limit switches.
uint8_t limit_switches_present = (original_limit_state ^ LIMIT_PIN) & LIMIT_MASK;
// Now carefully leave the limit switches
leave_limit_switch(
limit_switches_present & (1<<X_LIMIT_BIT),
limit_switches_present & (1<<Y_LIMIT_BIT),
limit_switches_present & (1<<Z_LIMIT_BIT));
}
/*
stepper.c - stepper motor driver: executes motion plans using stepper motors
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
Grbl is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Grbl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
and Philipp Tiefenbacher. */
#include "stepper.h"
#include "config.h"
#include "settings.h"
#include <math.h>
#include <stdlib.h>
#include <util/delay.h>
#include "nuts_bolts.h"
#include <avr/interrupt.h>
#include "planner.h"
#include "limits.h"
// Some useful constants
#define STEP_MASK ((1<<X_STEP_BIT)|(1<<Y_STEP_BIT)|(1<<Z_STEP_BIT)) // All step bits
#define DIRECTION_MASK ((1<<X_DIRECTION_BIT)|(1<<Y_DIRECTION_BIT)|(1<<Z_DIRECTION_BIT)) // All direction bits
#define STEPPING_MASK (STEP_MASK | DIRECTION_MASK) // All stepping-related bits (step/direction)
#define TICKS_PER_MICROSECOND (F_CPU/1000000)
#define CYCLES_PER_ACCELERATION_TICK ((TICKS_PER_MICROSECOND*1000000)/ACCELERATION_TICKS_PER_SECOND)
static block_t *current_block; // A pointer to the block currently being traced
// Variables used by The Stepper Driver Interrupt
static uint8_t out_bits; // The next stepping-bits to be output
static int32_t counter_x, // Counter variables for the bresenham line tracer
counter_y,
counter_z;
static uint32_t step_events_completed; // The number of step events executed in the current block
static volatile uint8_t busy; // true when SIG_OUTPUT_COMPARE1A is being serviced. Used to avoid retriggering that handler.
// Variables used by the trapezoid generation
static uint32_t cycles_per_step_event; // The number of machine cycles between each step event
static uint32_t trapezoid_tick_cycle_counter; // The cycles since last trapezoid_tick. Used to generate ticks at a steady
// pace without allocating a separate timer
static uint32_t trapezoid_adjusted_rate; // The current rate of step_events according to the trapezoid generator
static uint32_t min_safe_rate; // Minimum safe rate for full deceleration rate reduction step. Otherwise halves step_rate.
static uint8_t cycle_start; // Cycle start flag to indicate program start and block processing.
// __________________________
// /| |\ _________________ ^
// / | | \ /| |\ |
// / | | \ / | | \ s
// / | | | | | \ p
// / | | | | | \ e
// +-----+------------------------+---+--+---------------+----+ e
// | BLOCK 1 | BLOCK 2 | d
//
// time ----->
//
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates by block->rate_delta
// during the first block->accelerate_until step_events_completed, then keeps going at constant speed until
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
// The slope of acceleration is always +/- block->rate_delta and is applied at a constant rate following the midpoint rule
// by the trapezoid generator, which is called ACCELERATION_TICKS_PER_SECOND times per second.
static void set_step_events_per_minute(uint32_t steps_per_minute);
// Stepper state initialization
static void st_wake_up()
{
// Enable stepper driver interrupt
TIMSK1 |= (1<<OCIE1A);
}
// Stepper shutdown
static void st_go_idle()
{
// Cycle finished. Set flag to false.
cycle_start = false;
// Disable stepper driver interrupt
TIMSK1 &= ~(1<<OCIE1A);
// Force stepper dwell to lock axes for a defined amount of time to ensure the axes come to a complete
// stop and not drift from residual inertial forces at the end of the last movement.
}
// Initializes the trapezoid generator from the current block. Called whenever a new
// block begins.
static void trapezoid_generator_reset()
{
trapezoid_adjusted_rate = current_block->initial_rate;
min_safe_rate = current_block->rate_delta + (current_block->rate_delta >> 1); // 1.5 x rate_delta
trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2; // Start halfway for midpoint rule.
set_step_events_per_minute(trapezoid_adjusted_rate); // Initialize cycles_per_step_event
}
// This function determines an acceleration velocity change every CYCLES_PER_ACCELERATION_TICK by
// keeping track of the number of elapsed cycles during a de/ac-celeration. The code assumes that
// step_events occur significantly more often than the acceleration velocity iterations.
static uint8_t iterate_trapezoid_cycle_counter()
{
trapezoid_tick_cycle_counter += cycles_per_step_event;
if(trapezoid_tick_cycle_counter > CYCLES_PER_ACCELERATION_TICK) {
trapezoid_tick_cycle_counter -= CYCLES_PER_ACCELERATION_TICK;
return(true);
} else {
return(false);
}
}
#define DIR_FORWARD (0)
#define DIR_BACKWARD (1)
#define STEPPER_X_A1 (0x01<<PINB0)
#define STEPPER_X_A2 (0x01<<PINB1)
#define STEPPER_X_B1 (0x01<<PINB2)
#define STEPPER_X_B2 (0x01<<PINB3)
#define STEPPER_Y_A1 (0x01<<PIND4)
#define STEPPER_Y_A2 (0x01<<PIND5)
#define STEPPER_Y_B1 (0x01<<PIND6)
#define STEPPER_Y_B2 (0x01<<PIND7)
#define STEPPER_Z_A1 (0x01<<PINC0)
#define STEPPER_Z_A2 (0x01<<PINC1)
#define STEPPER_Z_B1 (0x01<<PINC2)
#define STEPPER_Z_B2 (0x01<<PINC3)
#define STEPPING_PORT_Z PORTC
#define STEPPING_PORT_Y PORTD
#define STEPPING_PORT_X PORTB
#define STEPPING_DDR_Z DDRC
#define STEPPING_DDR_Y DDRD
#define STEPPING_DDR_X DDRB
//#define STEPPER_X_ENABLE (0x01<<25)
//#define STEPPER_Y_ENABLE (0x01<<26)
#define ALL_STEPPER_PINS_X (STEPPER_X_A1|STEPPER_X_A2|STEPPER_X_B1|STEPPER_X_B2)
#define ALL_STEPPER_PINS_Y (STEPPER_Y_A1|STEPPER_Y_A2|STEPPER_Y_B1|STEPPER_Y_B2)
#define ALL_STEPPER_PINS_Z (STEPPER_Z_A1 |STEPPER_Z_A2|STEPPER_Z_B1|STEPPER_Z_B2)
const int stepper_pins[3][4] = {
{STEPPER_X_A1, STEPPER_X_A2, STEPPER_X_B1, STEPPER_X_B2},
{STEPPER_Y_A1, STEPPER_Y_A2, STEPPER_Y_B1, STEPPER_Y_B2},
{STEPPER_Z_A1, STEPPER_Z_A2, STEPPER_Z_B1, STEPPER_Z_B2},
};
void do_full_step(int direction, int axis)
{
static unsigned int crrnt_step[3] = {0,0,0};
if(direction == DIR_FORWARD) {
crrnt_step[axis] ++;
if (crrnt_step[axis] >= 4)
crrnt_step[axis] = 0;
}
else{
if(crrnt_step[axis] == 0)
crrnt_step[axis] = 4;
crrnt_step[axis] --;
}
if(axis == X_AXIS) { // Z_AXIS is on a different I/O port
switch(crrnt_step[axis]) {
case 0:
STEPPING_PORT_X &= ~(stepper_pins[axis][0]|stepper_pins[axis][2]);
STEPPING_PORT_X |= stepper_pins[axis][3] | stepper_pins[axis][1];
break;
case 1:
STEPPING_PORT_X &= ~(stepper_pins[axis][1] | stepper_pins[axis][2]);
STEPPING_PORT_X |= stepper_pins[axis][0] | stepper_pins[axis][3];
break;
case 2:
STEPPING_PORT_X &= ~(stepper_pins[axis][1] | stepper_pins[axis][3]);
STEPPING_PORT_X |= stepper_pins[axis][2] | stepper_pins[axis][0];
break;
case 3:
STEPPING_PORT_X &= ~(stepper_pins[axis][0] | stepper_pins[axis][3]);
STEPPING_PORT_X |= (stepper_pins[axis][1] | stepper_pins[axis][2]);
break;
return;
}
}
if(axis == Y_AXIS) {
switch(crrnt_step[axis]) {
case 0:
STEPPING_PORT_Y &= ~(stepper_pins[axis][0]|stepper_pins[axis][2]);
STEPPING_PORT_Y |= stepper_pins[axis][3] | stepper_pins[axis][1];
break;
case 1:
STEPPING_PORT_Y &= ~(stepper_pins[axis][1] | stepper_pins[axis][2]);
STEPPING_PORT_Y |= stepper_pins[axis][0] | stepper_pins[axis][3];
break;
case 2:
STEPPING_PORT_Y &= ~(stepper_pins[axis][1] | stepper_pins[axis][3]);
STEPPING_PORT_Y |= stepper_pins[axis][2] | stepper_pins[axis][0];
break;
case 3:
STEPPING_PORT_Y &= ~(stepper_pins[axis][0] | stepper_pins[axis][3]);
STEPPING_PORT_Y |= (stepper_pins[axis][1] | stepper_pins[axis][2]);
break;
return;
}
}
if(axis == Z_AXIS) { // Z_AXIS is on a different I/O port
switch(crrnt_step[axis]) {
case 0:
STEPPING_PORT_Z &= ~(stepper_pins[axis][0]|stepper_pins[axis][2]);
STEPPING_PORT_Z |= stepper_pins[axis][3] | stepper_pins[axis][1];
break;
case 1:
STEPPING_PORT_Z &= ~(stepper_pins[axis][1] | stepper_pins[axis][2]);
STEPPING_PORT_Z |= stepper_pins[axis][0] | stepper_pins[axis][3];
break;
case 2:
STEPPING_PORT_Z &= ~(stepper_pins[axis][1] | stepper_pins[axis][3]);
STEPPING_PORT_Z |= stepper_pins[axis][2] | stepper_pins[axis][0];
break;
case 3:
STEPPING_PORT_Z &= ~(stepper_pins[axis][0] | stepper_pins[axis][3]);
STEPPING_PORT_Z |= (stepper_pins[axis][1] | stepper_pins[axis][2]);
break;
return;
}
}
}
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. It is executed at the rate set with
// config_step_timer. It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
// It 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 three stepper outputs simultaneously with these two interrupts.
ISR(TIMER1_COMPA_vect)
{
if (busy) { return; } // The busy-flag is used to avoid reentering this interrupt
/*
// Set the direction pins a couple of nanoseconds before we step the steppers
STEPPING_PORT = (STEPPING_PORT & ~DIRECTION_MASK) | (out_bits & DIRECTION_MASK);
// Then pulse the stepping pins
STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | out_bits;
// Enable step pulse reset timer so that The Stepper Port Reset Interrupt can reset the signal after
// exactly settings.pulse_microseconds microseconds, independent of the main Timer1 prescaler.
TCNT2 = -(((settings.pulse_microseconds-2)*TICKS_PER_MICROSECOND) >> 3); // Reload timer counter
TCCR2B = (1<<CS21); // Begin timer2. Full speed, 1/8 prescaler
*/
if(out_bits & (1<<X_STEP_BIT)) {
if(out_bits & (1<<X_DIRECTION_BIT)) {
//do_half_step(DIR_FORWARD, X_AXIS);
do_full_step(DIR_FORWARD, X_AXIS);
} else {
// do_half_step(DIR_BACKWARD, X_AXIS);
do_full_step(DIR_BACKWARD, X_AXIS);
}
}
if(out_bits & (1<<Y_STEP_BIT)) {
if(out_bits & (1<<Y_DIRECTION_BIT)) {
// do_half_step(DIR_FORWARD, Y_AXIS);
do_full_step(DIR_FORWARD, Y_AXIS);
} else {
// do_half_step(DIR_BACKWARD, Y_AXIS);
do_full_step(DIR_BACKWARD, Y_AXIS);
}
}
if(out_bits & (1<<Z_STEP_BIT)) {
if(out_bits & (1<<Z_DIRECTION_BIT)) {
// do_half_step(DIR_FORWARD, Z_AXIS);
do_full_step(DIR_FORWARD, Z_AXIS);
} else {
// do_half_step(DIR_BACKWARD, Z_AXIS);
do_full_step(DIR_BACKWARD, Z_AXIS);
}
}
busy = true;
// Re-enable interrupts to allow ISR_TIMER2_OVERFLOW to trigger on-time and allow serial communications
// regardless of time in this handler. The following code prepares the stepper driver for the next
// step interrupt compare and will always finish before returning to the main program.
sei();
// If there is no current block, attempt to pop one from the buffer
if (current_block == NULL) {
// Anything in the buffer? If so, initialize next motion.
current_block = plan_get_current_block();
if (current_block != NULL) {
trapezoid_generator_reset();
counter_x = -(current_block->step_event_count >> 1);
counter_y = counter_x;
counter_z = counter_x;
step_events_completed = 0;
} else {
st_go_idle();
}
}
if (current_block != NULL) {
// Execute step displacement profile by bresenham line algorithm
out_bits = current_block->direction_bits;
counter_x += current_block->steps_x;
if (counter_x > 0) {
out_bits |= (1<<X_STEP_BIT);
counter_x -= current_block->step_event_count;
}
counter_y += current_block->steps_y;
if (counter_y > 0) {
out_bits |= (1<<Y_STEP_BIT);
counter_y -= current_block->step_event_count;
}
counter_z += current_block->steps_z;
if (counter_z > 0) {
out_bits |= (1<<Z_STEP_BIT);
counter_z -= current_block->step_event_count;
}
step_events_completed++; // Iterate step events
// While in block steps, check for de/ac-celeration events and execute them accordingly.
if (step_events_completed < current_block->step_event_count) {
// The trapezoid generator always checks step event location to ensure de/ac-celerations are
// executed and terminated at exactly the right time. This helps prevent over/under-shooting
// the target position and speed.
// NOTE: By increasing the ACCELERATION_TICKS_PER_SECOND in config.h, the resolution of the
// discrete velocity changes increase and accuracy can increase as well to a point. Numerical
// round-off errors can effect this, if set too high. This is important to note if a user has
// very high acceleration and/or feedrate requirements for their machine.
if (step_events_completed < current_block->accelerate_until) {
// Iterate cycle counter and check if speeds need to be increased.
if ( iterate_trapezoid_cycle_counter() ) {
trapezoid_adjusted_rate += current_block->rate_delta;
if (trapezoid_adjusted_rate >= current_block->nominal_rate) {
// Reached nominal rate a little early. Cruise at nominal rate until decelerate_after.
trapezoid_adjusted_rate = current_block->nominal_rate;
}
set_step_events_per_minute(trapezoid_adjusted_rate);
}
} else if (step_events_completed >= current_block->decelerate_after) {
// Reset trapezoid tick cycle counter to make sure that the deceleration is performed the
// same every time. Reset to CYCLES_PER_ACCELERATION_TICK/2 to follow the midpoint rule for
// an accurate approximation of the deceleration curve.
if (step_events_completed == current_block-> decelerate_after) {
trapezoid_tick_cycle_counter = CYCLES_PER_ACCELERATION_TICK/2;
} else {
// Iterate cycle counter and check if speeds need to be reduced.
if ( iterate_trapezoid_cycle_counter() ) {
// NOTE: We will only do a full speed reduction if the result is more than the minimum safe
// rate, initialized in trapezoid reset as 1.5 x rate_delta. Otherwise, reduce the speed by
// half increments until finished. The half increments are guaranteed not to exceed the
// CNC acceleration limits, because they will never be greater than rate_delta. This catches
// small errors that might leave steps hanging after the last trapezoid tick or a very slow
// step rate at the end of a full stop deceleration in certain situations. The half rate
// reductions should only be called once or twice per block and create a nice smooth
// end deceleration.
if (trapezoid_adjusted_rate > min_safe_rate) {
trapezoid_adjusted_rate -= current_block->rate_delta;
} else {
trapezoid_adjusted_rate >>= 1; // Bit shift divide by 2
}
if (trapezoid_adjusted_rate < current_block->final_rate) {
// Reached final rate a little early. Cruise to end of block at final rate.
trapezoid_adjusted_rate = current_block->final_rate;
}
set_step_events_per_minute(trapezoid_adjusted_rate);
}
}
} else {
// No accelerations. Make sure we cruise exactly at the nominal rate.
if (trapezoid_adjusted_rate != current_block->nominal_rate) {
trapezoid_adjusted_rate = current_block->nominal_rate;
set_step_events_per_minute(trapezoid_adjusted_rate);
}
}
} else {
// If current block is finished, reset pointer
current_block = NULL;
plan_discard_current_block();
}
}
// out_bits ^= settings.invert_mask; // Apply stepper invert mask
busy=false;
}
// This interrupt is set up by ISR_TIMER1_COMPAREA when it sets the motor port bits. It resets
// the motor port after a short period (settings.pulse_microseconds) completing one step cycle.
// TODO: It is possible for the serial interrupts to delay this interrupt by a few microseconds, if
// they execute right before this interrupt. Not a big deal, but could use some TLC at some point.
ISR(TIMER2_OVF_vect)
{
// Reset stepping pins (leave the direction pins)
// STEPPING_PORT = (STEPPING_PORT & ~STEP_MASK) | (settings.invert_mask & STEP_MASK);
TCCR2B = 0; // Disable Timer2 to prevent re-entering this interrupt when it's not needed.
}
// Initialize and start the stepper motor subsystem
void st_init()
{
// Configure directions of interface pins
// STEPPING_DDR |= STEPPING_MASK;
// STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | settings.invert_mask;
// STEPPERS_DISABLE_DDR |= 1<<STEPPERS_DISABLE_BIT;
STEPPING_DDR_X |= ALL_STEPPER_PINS_X;
STEPPING_PORT_X |= ALL_STEPPER_PINS_X;
STEPPING_DDR_Y |= ALL_STEPPER_PINS_Y;
STEPPING_PORT_Y |= ALL_STEPPER_PINS_Y;
STEPPING_DDR_Z |= ALL_STEPPER_PINS_Z;
STEPPING_PORT_Z |= ALL_STEPPER_PINS_Z;
// waveform generation = 0100 = CTC
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1A &= ~(1<<WGM11);
TCCR1A &= ~(1<<WGM10);
// output mode = 00 (disconnected)
TCCR1A &= ~(3<<COM1A0);
TCCR1A &= ~(3<<COM1B0);
// Configure Timer 2
TCCR2A = 0; // Normal operation
TCCR2B = 0; // Disable timer until needed.
TIMSK2 |= (1<<TOIE2); // Enable Timer2 interrupt flag
set_step_events_per_minute(MINIMUM_STEPS_PER_MINUTE);
trapezoid_tick_cycle_counter = 0;
current_block = NULL;
busy = false;
// Start in the idle state
st_go_idle();
}
// Block until all buffered steps are executed
void st_synchronize()
{
while(plan_get_current_block()) { sleep_mode(); }
}
// Configures the prescaler and ceiling of timer 1 to produce the given rate as accurately as possible.
// Returns the actual number of cycles per interrupt
static uint32_t config_step_timer(uint32_t cycles)
{
uint16_t ceiling;
uint16_t prescaler;
uint32_t actual_cycles;
if (cycles <= 0xffffL) {
ceiling = cycles;
prescaler = 0; // prescaler: 0
actual_cycles = ceiling;
} else if (cycles <= 0x7ffffL) {
ceiling = cycles >> 3;
prescaler = 1; // prescaler: 8
actual_cycles = ceiling * 8L;
} else if (cycles <= 0x3fffffL) {
ceiling = cycles >> 6;
prescaler = 2; // prescaler: 64
actual_cycles = ceiling * 64L;
} else if (cycles <= 0xffffffL) {
ceiling = (cycles >> 8);
prescaler = 3; // prescaler: 256
actual_cycles = ceiling * 256L;
} else if (cycles <= 0x3ffffffL) {
ceiling = (cycles >> 10);
prescaler = 4; // prescaler: 1024
actual_cycles = ceiling * 1024L;
} else {
// Okay, that was slower than we actually go. Just set the slowest speed
ceiling = 0xffff;
prescaler = 4;
actual_cycles = 0xffff * 1024;
}
// Set prescaler
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | ((prescaler+1)<<CS10);
// Set ceiling
OCR1A = ceiling;
return(actual_cycles);
}
static void set_step_events_per_minute(uint32_t steps_per_minute)
{
if (steps_per_minute < MINIMUM_STEPS_PER_MINUTE) { steps_per_minute = MINIMUM_STEPS_PER_MINUTE; }
cycles_per_step_event = config_step_timer((TICKS_PER_MICROSECOND*1000000*60)/steps_per_minute);
}
void st_go_home()
{
limits_go_home();
plan_set_current_position(0,0,0);
}
// Planner external interface to start stepper interrupt and execute the blocks in queue.
void st_cycle_start()
{
if (!cycle_start) {
cycle_start = true;
st_wake_up();
}
}
@offon
Copy link

offon commented Feb 13, 2013

Have problem whe try to make file:

"make.exe" all
avr-gcc -Wall -Os -DF_CPU=16000000 -mmcu=atmega2560 -I. -ffunction-sections -c stepper.c -o stepper.o
stepper.c:37:1: warning: "STEP_MASK" redefined
In file included from stepper.c:25:
stepper.h:29:1: warning: this is the location of the previous definition
stepper.c:38:1: warning: "DIRECTION_MASK" redefined
stepper.h:30:1: warning: this is the location of the previous definition
stepper.c:89: error: static declaration of 'st_go_idle' follows non-static declaration
stepper.h:38: error: previous declaration of 'st_go_idle' was here
stepper.c: In function 'st_go_home':
stepper.c:505: error: too few arguments to function 'plan_set_current_position'
make.exe: *** [stepper.o] Error 1

Process Exit Code: 2
Time Taken: 00:00

Can you help me?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment