From 62b5bb01dc728b7b6915d4380dd912d27e2c5a79 Mon Sep 17 00:00:00 2001 From: Markus Hitter Date: Sun, 12 Jun 2016 19:27:18 +0200 Subject: [PATCH] Attic: tar up 'accel_clock'. --- attic/accel_clock.tar.gz | Bin 0 -> 16028 bytes ...eeaacf813baf387316a6cbb31b7c52dcc6fd.patch | 363 ------ attic/accel_clock/dda.c | 1045 ----------------- attic/accel_clock/dda.h | 227 ---- 4 files changed, 1635 deletions(-) create mode 100644 attic/accel_clock.tar.gz delete mode 100644 attic/accel_clock/apply-to-5df8eeaacf813baf387316a6cbb31b7c52dcc6fd.patch delete mode 100644 attic/accel_clock/dda.c delete mode 100644 attic/accel_clock/dda.h diff --git a/attic/accel_clock.tar.gz b/attic/accel_clock.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..37532829e496b260ccbcfddbd929e815a45ec67f GIT binary patch literal 16028 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 -Date: Mon, 25 Mar 2013 11:19:50 +0100 -Subject: Implement ACCELERATION_CLOCK. - -This was tried a lot, with the following results: - -1. Doing acceleration calculations (and later, curvature - calculations) in an clock based interrupt instead of - the step interrupt is an excellent idea. Achievable - step rate raised from about 16.000 steps/second - to 48.000 steps/second. - -2. The approach to calculate desired speeds from movement time - did work not so well. While it's possible to keep geometrical - accuracy (continue at minimum speed or stop before decelerating - to full stop in case the timing doesn't match), timing - calculations are way to inprecise to match a movement's end - within +- one step. Missing the movement end by more than 10 - steps was observed regularly. - -3. Major reasons for 2. are apparently inprecise distance - and timer calculations. Even accumulating just 1% of - inprecision means more than 100 missed steps at the end - of a long move. - -4. To avoid 2., the next approach shall turn back to calculate - speeds based on executed steps, like it was done in the step - interrupt. - -ACCELERATION_CLOCK is an approach different from the other ones. -Acceleration isn't calculated as part of the step interrupt, but -on clock based intervals (every 1ms or 2 ms). This not only -allows to do these calculations with 16 bit integers, it also -reduces the number of these expensive calculations at high speeds. -The step interrupt becomes very lean, doing only Bresenham -calculations, and should allow much higher step rates (several -steps can be done per acceleration calculation). 500 to 1000 -speed calculations per second should be more than sufficient -to give a smooth ride. - -It should be possible to combine this with ACCELERATION_TEMPORAL -to give equally spaced steps for _every_ stepper for an even -smoother ride. - -More ACCELERATION_CLOCK. - -ACCELERATION_CLOCK: add more refinements and debug code. - -For yet unknown reasons, this strategy falls far below -expectations. Configured to 1280 steps/mm, the code works -for up to about 500 mm/min, only. ACCELERATION_RAMPING does, -despite the expensive acceleration calculation in the step -interrupt, manage to move 760 mm/min. - -For finding the cause, I tried to comment out virtually all -code out of dda_step() as well as the clock interrupt. Just -Bresenham for the X-axis and setTimer() left, the code still -acts funny at pretty much the same feedrates. No enhancement -at all. - -The debug code currently put in sends a 's' on every step -interrupt, a '.' on every clock interrupt. At higher speeds, -one should see one '.' every 20 's' or similar. However, -from time to time one sees consecutive clock interrupts, -apparently step interrupts fail to happen in some -situations. - -The good thing: acceleration works reasonably fine now, the -situation with clock ticks, and along with them, speed changes, -happening more often than actual steps seems to be solved. In -earlier code, the first speed calculation right after movement -start caused a long pause, leading to something like a delayed, -unaccelerated movement. - -Get ACCELERATION_CLOCK finally working. Yikes! - -The problem was: the step interrupt unlocked interrupts and -if this resulted in a rush of pending other interrupts, -it took a looong time until the step timer was set again. ---- - dda.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- - dda.h | 13 ++++++ - 2 files changed, 179 insertions(+), 3 deletions(-) - -diff --git a/dda.c b/dda.c -index a02f37d..e84f91e 100644 ---- a/dda.c -+++ b/dda.c -@@ -25,6 +25,11 @@ - #ifdef DC_EXTRUDER - #include "heater.h" - #endif -+#include "delay.h" -+ -+#if defined ACCELERATION_RAMPING && defined ACCELERATION_CLOCK -+ #error Cant define ACCELERATION_RAMPING and ACCELERATION_CLOCK at the same time. -+#endif - - /* - position tracking -@@ -347,6 +352,82 @@ void dda_create(DDA *dda, TARGET *target, DDA *prev_dda) { - #ifdef LOOKAHEAD - dda_join_moves(prev_dda, dda); - #endif -+ #elif defined ACCELERATION_CLOCK -+ uint16_t candidate; -+ -+ // Total time of the unaccelerated move. -+ // 1 um/ms = 1 mm/s = 60 mm/min -+ dda->time_total = distance * (60 / TICK_TIME_MS) / target->F; -+ -+ // To avoid overspeeding an axis, movement takes at least as -+ // long as the slowest axis requires. -+ candidate = x_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_X; -+ if (candidate > dda->time_total) -+ dda->time_total = candidate; -+ candidate = y_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Y; -+ if (candidate > dda->time_total) -+ dda->time_total = candidate; -+ candidate = z_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Z; -+ if (candidate > dda->time_total) -+ dda->time_total = candidate; -+ candidate = e_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_E; -+ if (candidate > dda->time_total) -+ dda->time_total = candidate; -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("time total %u\n"), dda->time_total); -+ -+ // Re-calculate speeds, as they might have changed. -+ dda->F_start = 0; -+ dda->F_end = 0; -+ dda->F_max = distance * (60 / TICK_TIME_MS) / dda->time_total; -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("corrected F_max %u\n"), dda->F_max); -+ -+ // Time in clock ticks required for acceleration. -+ dda->time_accel = ((uint32_t)(dda->F_max - dda->F_start)) * -+ ((uint32_t)(1000 / TICK_TIME_MS)) / -+ ((uint32_t)(60 * ACCELERATION)); -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("time accel %u\n"), dda->time_accel); -+ -+ // Time in clock ticks required for deceleration. -+ dda->time_decel = ((uint32_t)(dda->F_max - dda->F_end)) * -+ ((uint32_t)(1000 / TICK_TIME_MS)) / -+ ((uint32_t)(60 * ACCELERATION)); -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("time decel %u\n"), dda->time_decel); -+ -+ // Add time required for acceleration / deceleration. -+ dda->time_total += dda->time_accel / 2 + dda->time_decel / 2; -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("time total w. accel %u\n"), dda->time_total); -+ dda->time_decel = dda->time_total - dda->time_decel; -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("time decel2 %u\n"), dda->time_decel); -+ -+ // UGLY HACK: to compensate for inaccurate ac- and deceleration -+ // time calculations, add a margin here: -+// dda->time_decel += (dda->time_accel >> 3); -+//sersendf_P(PSTR("time decel hacked %u\n"), dda->time_decel); delay_ms(10); -+ -+ // This is the ratio between F (in mm/min) and c (in CPU clock ticks) -+ // and is constant during the entire move, even on curved movements. -+ // Essentially, it's the step rate of the fastest stepping stepper -+ // of the entire move. -+ // For linear movements it's simple: -+ dda->f_to_c = (distance * 2400L) / dda->total_steps * (F_CPU / 40000) << 8; -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ sersendf_P(PSTR("f_to_c %lu\n"), dda->f_to_c); -+ -+ // Initial step delays. As we can't start with zero speed, advance -+ // all calculations by half a clock tick. -+ // v = a * t; c = 1 / v; -+// Don't forget F_start! -+ dda->c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * TICK_TIME_MS / 1000UL); -+ -+sersendf_P(PSTR("c_min new %lu\n"), dda->f_to_c / target->F); delay_ms(10); -+sersendf_P(PSTR("c_min trad %lu\n"), (move_duration / target->F) << 8); delay_ms(10); -+ - #elif defined ACCELERATION_TEMPORAL - // TODO: limit speed of individual axes to MAXIMUM_FEEDRATE - // TODO: calculate acceleration/deceleration for each axis -@@ -445,6 +526,10 @@ void dda_start(DDA *dda) { - else - setTimer(move_state.c >> 8); - #else -+ #ifdef ACCELERATION_CLOCK -+ move_state.time_current = 0; -+ move_state.ticks_since_step = 0; -+ #endif - setTimer(dda->c >> 8); - #endif - } -@@ -537,7 +622,7 @@ void dda_step(DDA *dda) { - } - #endif - -- #if STEP_INTERRUPT_INTERRUPTIBLE -+ #if defined STEP_INTERRUPT_INTERRUPTIBLE && ! defined ACCELERATION_CLOCK - // Since we have sent steps to all the motors that will be stepping - // and the rest of this function isn't so time critical, this interrupt - // can now be interruptible by other interrupts. -@@ -582,7 +667,6 @@ void dda_step(DDA *dda) { - //if (move_state.step_no == 0) { - // sersendf_P(PSTR("\r\nc %lu c_min %lu n %d"), dda->c, dda->c_min, move_state.n); - //} -- - recalc_speed = 0; - if (move_state.step_no < dda->rampup_steps) { - if (move_state.n < 0) // wrong ramp direction -@@ -678,6 +762,11 @@ void dda_step(DDA *dda) { - #endif - ) { - dda->live = 0; -+ #ifdef ACCELERATION_CLOCK -+ if (dda->time_total - move_state.time_current > 1) -+ sersendf_P(PSTR("undershoot by %u ticks\n"), -+ dda->time_total - move_state.time_current); -+ #endif - #ifdef LOOKAHEAD - // If look-ahead was using this move, it could have missed our activation: - // make sure the ids do not match. -@@ -701,6 +790,9 @@ void dda_step(DDA *dda) { - else - setTimer(move_state.c >> 8); - #else -+ #ifdef ACCELERATION_CLOCK -+ move_state.ticks_since_step = 0; -+ #endif - setTimer(dda->c >> 8); - #endif - -@@ -728,6 +820,8 @@ void dda_clock() { - static DDA *last_dda = NULL; - static uint8_t endstop_stop = 0; ///< Stop due to endstop trigger - -+ move_state.time_current++; -+ - dda = queue_current_movement(); - if (dda != last_dda) { - move_state.debounce_count_xmin = move_state.debounce_count_ymin = -@@ -742,8 +836,11 @@ void dda_clock() { - - // Lengthy calculations ahead! - // Make sure we didn't re-enter, then allow nested interrupts. -- if (busy) -+ if (busy) { -+ if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) -+ serial_writechar('B'); - return; -+ } - busy = 1; - sei(); - -@@ -826,6 +923,72 @@ void dda_clock() { - } - } /* if (endstop_stop == 0) */ - -+ #ifdef ACCELERATION_CLOCK -+ uint32_t new_c = 0; -+ static uint8_t plateau_done = 0; -+ -+ // Overtime? -+ if (move_state.time_current > dda->time_total) { -+ // Keep it short to have at least a chance to get it sent. -+ #warning Das hier hört nicht auf. -+ //serial_writestr_P(PSTR("ot")); -+ move_state.time_current = dda->time_total; -+ } -+ // Acceleration time. -+ else if (move_state.time_current < dda->time_accel) { -+ // v = a * t; c = 1 / v; -+ new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * (uint32_t)move_state.time_current * TICK_TIME_MS / 1000UL); -+ plateau_done = 0; -+serial_writechar('a'); -+ } -+ else if (move_state.time_current > dda->time_decel) { -+ uint32_t dt = (uint32_t)dda->time_total - (uint32_t)move_state.time_current; -+ -+ if (dt < 1) // we undershot *sigh* -+ dt = 1; -+ // v = a * t; c = 1 / v; -+ new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * dt * TICK_TIME_MS / 1000UL); -+serial_writechar('d'); -+ plateau_done = 0; -+ -+ } -+ // Plateau time. -+ else if (plateau_done == 0) { -+ new_c = dda->f_to_c / dda->F_max; -+ plateau_done = 1; -+serial_writechar('r'); -+ } -+ else -+serial_writechar('.'); -+ -+ if (new_c) { -+ ATOMIC_START -+ dda->c = new_c; -+ ATOMIC_END -+ } -+ -+ // Set up or readjust the timer if actual steps happen too slowly. dda_step() -+ // resets ticks_since_step to zero, while we increment it here, so we have an -+ // idea on how much time is gone since the last actual step. -+ // 300 = minimum time setTimer requires. -+if (dda->time_total == move_state.time_current) -+sersendf_P(PSTR("overshoot by %lu steps\n"), move_state.x_steps); -+ if (move_state.ticks_since_step) { -+ if ((dda->c >> 8) < ((uint32_t)move_state.ticks_since_step * TICK_TIME) + 300UL) { -+ // We're too late already, go as quick as possbile. -+ setTimer(300UL); -+serial_writechar('-'); -+ } -+ else { -+ // TODO: we ignore the time taken until we get here. -+ setTimer((dda->c >> 8) - ((uint32_t)move_state.ticks_since_step * TICK_TIME)); -+serial_writechar('+'); -+ } -+ } -+ sei(); // setTimer locks interrupts -+ move_state.ticks_since_step++; -+ #endif -+ - cli(); // Compensate sei() above. - busy = 0; - } -diff --git a/dda.h b/dda.h -index 5bc4238..76963ac 100644 ---- a/dda.h -+++ b/dda.h -@@ -77,6 +77,10 @@ typedef struct { - /// tracking variable - int32_t n; - #endif -+ #ifdef ACCELERATION_CLOCK -+ uint16_t time_current; -+ uint8_t ticks_since_step; -+ #endif - #ifdef ACCELERATION_TEMPORAL - uint32_t x_time; ///< time of the last x step - uint32_t y_time; ///< time of the last y step -@@ -160,6 +164,15 @@ typedef struct { - uint8_t id; - #endif - #endif -+ #ifdef ACCELERATION_CLOCK -+ uint16_t F_start; -+ uint16_t F_end; -+ uint16_t F_max; -+ uint16_t time_accel; ///< in clock ticks (1ms or 2ms) -+ uint16_t time_decel; ///< in clock ticks (1ms or 2ms) -+ uint16_t time_total; ///< in clock ticks (1ms or 2ms) -+ uint32_t f_to_c; -+ #endif - #ifdef ACCELERATION_TEMPORAL - uint32_t x_step_interval; ///< time between steps on X axis - uint32_t y_step_interval; ///< time between steps on Y axis --- -1.8.3.2 - diff --git a/attic/accel_clock/dda.c b/attic/accel_clock/dda.c deleted file mode 100644 index e84f91e..0000000 --- a/attic/accel_clock/dda.c +++ /dev/null @@ -1,1045 +0,0 @@ -#include "dda.h" - -/** \file - \brief Digital differential analyser - this is where we figure out which steppers need to move, and when they need to move -*/ - -#include -#include -#include -#include - -#include "dda_maths.h" -#include "dda_lookahead.h" -#include "timer.h" -#include "serial.h" -#include "sermsg.h" -#include "gcode_parse.h" -#include "dda_queue.h" -#include "debug.h" -#include "sersendf.h" -#include "pinio.h" -#include "memory_barrier.h" -//#include "graycode.c" - -#ifdef DC_EXTRUDER - #include "heater.h" -#endif -#include "delay.h" - -#if defined ACCELERATION_RAMPING && defined ACCELERATION_CLOCK - #error Cant define ACCELERATION_RAMPING and ACCELERATION_CLOCK at the same time. -#endif - -/* - position tracking -*/ - -/// \var startpoint -/// \brief target position of last move in queue -TARGET startpoint __attribute__ ((__section__ (".bss"))); - -/// \var startpoint_steps -/// \brief target position of last move in queue, expressed in steps -TARGET startpoint_steps __attribute__ ((__section__ (".bss"))); - -/// \var current_position -/// \brief actual position of extruder head -/// \todo make current_position = real_position (from endstops) + offset from G28 and friends -TARGET current_position __attribute__ ((__section__ (".bss"))); - -/// \var move_state -/// \brief numbers for tracking the current state of movement -MOVE_STATE move_state __attribute__ ((__section__ (".bss"))); - -/*! Inititalise DDA movement structures -*/ -void dda_init(void) { - // set up default feedrate - if (startpoint.F == 0) - startpoint.F = next_target.target.F = SEARCH_FEEDRATE_Z; - - #ifdef ACCELERATION_RAMPING - move_state.n = 1; - move_state.c = ((uint32_t)((double)F_CPU / sqrt((double)(STEPS_PER_M_X * ACCELERATION / 1000.)))) << 8; - #endif -} - -/*! Distribute a new startpoint to DDA's internal structures without any movement. - - This is needed for example after homing or a G92. The new location must be in startpoint already. -*/ -void dda_new_startpoint(void) { - startpoint_steps.X = um_to_steps_x(startpoint.X); - startpoint_steps.Y = um_to_steps_y(startpoint.Y); - startpoint_steps.Z = um_to_steps_z(startpoint.Z); - startpoint_steps.E = um_to_steps_e(startpoint.E); -} - -/*! CREATE a dda given current_position and a target, save to passed location so we can write directly into the queue - \param *dda pointer to a dda_queue entry to overwrite - \param *target the target position of this move - - \ref startpoint the beginning position of this move - - This function does a /lot/ of math. It works out directions for each axis, distance travelled, the time between the first and second step - - It also pre-fills any data that the selected accleration algorithm needs, and can be pre-computed for the whole move. - - This algorithm is probably the main limiting factor to print speed in terms of firmware limitations -*/ -void dda_create(DDA *dda, TARGET *target, DDA *prev_dda) { - uint32_t steps, x_delta_um, y_delta_um, z_delta_um, e_delta_um; - uint32_t distance, c_limit, c_limit_calc; - #ifdef LOOKAHEAD - // Number the moves to identify them; allowed to overflow. - static uint8_t idcnt = 0; - #endif - - // initialise DDA to a known state - dda->allflags = 0; - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writestr_P(PSTR("\n{DDA_CREATE: [")); - - // we end at the passed target - memcpy(&(dda->endpoint), target, sizeof(TARGET)); - - #ifdef LOOKAHEAD - // Set the start and stop speeds to zero for now = full stops between - // moves. Also fallback if lookahead calculations fail to finish in time. - dda->F_start = 0; - dda->F_end = 0; - // Give this move an identifier. - dda->id = idcnt++; - #endif - -// TODO TODO: We should really make up a loop for all axes. -// Think of what happens when a sixth axis (multi colour extruder) -// appears? - x_delta_um = (uint32_t)labs(target->X - startpoint.X); - y_delta_um = (uint32_t)labs(target->Y - startpoint.Y); - z_delta_um = (uint32_t)labs(target->Z - startpoint.Z); - - steps = um_to_steps_x(target->X); - dda->x_delta = labs(steps - startpoint_steps.X); - startpoint_steps.X = steps; - steps = um_to_steps_y(target->Y); - dda->y_delta = labs(steps - startpoint_steps.Y); - startpoint_steps.Y = steps; - steps = um_to_steps_z(target->Z); - dda->z_delta = labs(steps - startpoint_steps.Z); - startpoint_steps.Z = steps; - - dda->x_direction = (target->X >= startpoint.X)?1:0; - dda->y_direction = (target->Y >= startpoint.Y)?1:0; - dda->z_direction = (target->Z >= startpoint.Z)?1:0; - - if (target->e_relative) { - e_delta_um = labs(target->E); - dda->e_delta = labs(um_to_steps_e(target->E)); - dda->e_direction = (target->E >= 0)?1:0; - } - else { - e_delta_um = (uint32_t)labs(target->E - startpoint.E); - steps = um_to_steps_e(target->E); - dda->e_delta = labs(steps - startpoint_steps.E); - startpoint_steps.E = steps; - dda->e_direction = (target->E >= startpoint.E)?1:0; - } - - #ifdef LOOKAHEAD - // Also displacements in micrometers, but for the lookahead alogrithms. - dda->delta.X = target->X - startpoint.X; - dda->delta.Y = target->Y - startpoint.Y; - dda->delta.Z = target->Z - startpoint.Z; - dda->delta.E = target->e_relative ? target->E : target->E - startpoint.E; - #endif - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("%ld,%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z, target->E - startpoint.E); - - dda->total_steps = dda->x_delta; - if (dda->y_delta > dda->total_steps) - dda->total_steps = dda->y_delta; - if (dda->z_delta > dda->total_steps) - dda->total_steps = dda->z_delta; - if (dda->e_delta > dda->total_steps) - dda->total_steps = dda->e_delta; - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("ts:%lu"), dda->total_steps); - - if (dda->total_steps == 0) { - dda->nullmove = 1; - } - else { - // get steppers ready to go - power_on(); - stepper_enable(); - x_enable(); - y_enable(); - // Z is enabled in dda_start() - e_enable(); - - // since it's unusual to combine X, Y and Z changes in a single move on reprap, check if we can use simpler approximations before trying the full 3d approximation. - if (z_delta_um == 0) - distance = approx_distance(x_delta_um, y_delta_um); - else if (x_delta_um == 0 && y_delta_um == 0) - distance = z_delta_um; - else - distance = approx_distance_3(x_delta_um, y_delta_um, z_delta_um); - - if (distance < 2) - distance = e_delta_um; - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR(",ds:%lu"), distance); - - #ifdef ACCELERATION_TEMPORAL - // bracket part of this equation in an attempt to avoid overflow: 60 * 16MHz * 5mm is >32 bits - uint32_t move_duration, md_candidate; - - move_duration = distance * ((60 * F_CPU) / (target->F * 1000UL)); - md_candidate = dda->x_delta * ((60 * F_CPU) / (MAXIMUM_FEEDRATE_X * 1000UL)); - if (md_candidate > move_duration) - move_duration = md_candidate; - md_candidate = dda->y_delta * ((60 * F_CPU) / (MAXIMUM_FEEDRATE_Y * 1000UL)); - if (md_candidate > move_duration) - move_duration = md_candidate; - md_candidate = dda->z_delta * ((60 * F_CPU) / (MAXIMUM_FEEDRATE_Z * 1000UL)); - if (md_candidate > move_duration) - move_duration = md_candidate; - md_candidate = dda->e_delta * ((60 * F_CPU) / (MAXIMUM_FEEDRATE_E * 1000UL)); - if (md_candidate > move_duration) - move_duration = md_candidate; - #else - // pre-calculate move speed in millimeter microseconds per step minute for less math in interrupt context - // mm (distance) * 60000000 us/min / step (total_steps) = mm.us per step.min - // note: um (distance) * 60000 == mm * 60000000 - // so in the interrupt we must simply calculate - // mm.us per step.min / mm per min (F) = us per step - - // break this calculation up a bit and lose some precision because 300,000um * 60000 is too big for a uint32 - // calculate this with a uint64 if you need the precision, but it'll take longer so routines with lots of short moves may suffer - // 2^32/6000 is about 715mm which should be plenty - - // changed * 10 to * (F_CPU / 100000) so we can work in cpu_ticks rather than microseconds. - // timer.c setTimer() routine altered for same reason - - // changed distance * 6000 .. * F_CPU / 100000 to - // distance * 2400 .. * F_CPU / 40000 so we can move a distance of up to 1800mm without overflowing - uint32_t move_duration = ((distance * 2400) / dda->total_steps) * (F_CPU / 40000); - #endif - - // similarly, find out how fast we can run our axes. - // do this for each axis individually, as the combined speed of two or more axes can be higher than the capabilities of a single one. - c_limit = 0; - // check X axis - c_limit_calc = ((x_delta_um * 2400L) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_X) << 8; - if (c_limit_calc > c_limit) - c_limit = c_limit_calc; - // check Y axis - c_limit_calc = ((y_delta_um * 2400L) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Y) << 8; - if (c_limit_calc > c_limit) - c_limit = c_limit_calc; - // check Z axis - c_limit_calc = ((z_delta_um * 2400L) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Z) << 8; - if (c_limit_calc > c_limit) - c_limit = c_limit_calc; - // check E axis - c_limit_calc = ((e_delta_um * 2400L) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_E) << 8; - if (c_limit_calc > c_limit) - c_limit = c_limit_calc; - - #ifdef ACCELERATION_REPRAP - // c is initial step time in IOclk ticks - dda->c = (move_duration / startpoint.F) << 8; - if (dda->c < c_limit) - dda->c = c_limit; - dda->end_c = (move_duration / target->F) << 8; - if (dda->end_c < c_limit) - dda->end_c = c_limit; - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR(",md:%lu,c:%lu"), move_duration, dda->c >> 8); - - if (dda->c != dda->end_c) { - uint32_t stF = startpoint.F / 4; - uint32_t enF = target->F / 4; - // now some constant acceleration stuff, courtesy of http://www.embedded.com/columns/technicalinsights/56800129?printable=true - uint32_t ssq = (stF * stF); - uint32_t esq = (enF * enF); - int32_t dsq = (int32_t) (esq - ssq) / 4; - - uint8_t msb_ssq = msbloc(ssq); - uint8_t msb_tot = msbloc(dda->total_steps); - - // the raw equation WILL overflow at high step rates, but 64 bit math routines take waay too much space - // at 65536 mm/min (1092mm/s), ssq/esq overflows, and dsq is also close to overflowing if esq/ssq is small - // but if ssq-esq is small, ssq/dsq is only a few bits - // we'll have to do it a few different ways depending on the msb locations of each - if ((msb_tot + msb_ssq) <= 30) { - // we have room to do all the multiplies first - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writechar('A'); - dda->n = ((int32_t) (dda->total_steps * ssq) / dsq) + 1; - } - else if (msb_tot >= msb_ssq) { - // total steps has more precision - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writechar('B'); - dda->n = (((int32_t) dda->total_steps / dsq) * (int32_t) ssq) + 1; - } - else { - // otherwise - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writechar('C'); - dda->n = (((int32_t) ssq / dsq) * (int32_t) dda->total_steps) + 1; - } - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("\n{DDA:CA end_c:%lu, n:%ld, md:%lu, ssq:%lu, esq:%lu, dsq:%lu, msbssq:%u, msbtot:%u}\n"), dda->end_c >> 8, dda->n, move_duration, ssq, esq, dsq, msb_ssq, msb_tot); - - dda->accel = 1; - } - else - dda->accel = 0; - #elif defined ACCELERATION_RAMPING - // yes, this assumes always the x axis as the critical one regarding acceleration. If we want to implement per-axis acceleration, things get tricky ... - dda->c_min = (move_duration / target->F) << 8; - if (dda->c_min < c_limit) - dda->c_min = c_limit; - - /** - Assuming: F is in mm/min, STEPS_PER_M_X is in steps/m, ACCELERATION is in mm/s² - Given: - - Velocity v at time t given acceleration a: v(t) = a*t - - Displacement s at time t given acceleration a: s(t) = 1/2 * a * t² - - Displacement until reaching target velocity v: s = 1/2 * (v² / a) - - Final result: steps needed to reach velocity v given acceleration a: - steps = (STEPS_PER_M_X * F^2) / (7200000 * ACCELERATION) - To keep precision, break up in floating point and integer part: - F^2 * (int)(STEPS_PER_M_X / (7200000 * ACCELERATION)) - Note: the floating point part is static so its calculated during compilation. - Note 2: the floating point part will be smaller than one, invert it: - steps = F^2 / (int)((7200000 * ACCELERATION) / STEPS_PER_M_X) - Note 3: As mentioned, setting F to 65535 or larger will overflow the - calculation. Make sure this does not happen. - Note 4: Anyone trying to run their machine at 65535 mm/min > 1m/s is nuts - */ - if (target->F > 65534) target->F = 65534; - // Note: this is inaccurate for several reasons: - // - target->F isn't reverse-calculated from c_limit, so speed - // reductions due to slow axes are ignored. - // - target->F means the speed of all axes combined, not the speed - // of the fast axis, which is taken into account here. - // The good thing: taking target->F means rampup_steps is always - // equal or larger than the number of steps required for acceleration, - // so we can use it when also limiting max speed according to c_limit. - dda->rampup_steps = ACCELERATE_RAMP_LEN(target->F); - // Quick hack: we do not do Z move joins as jerk on the Z axis is undesirable; - // as the ramp length is calculated for XY, its incorrect for Z: apply the original - // 'fix' to simply specify a large enough ramp for any speed. - if (x_delta_um == 0 && y_delta_um == 0) { - dda->rampup_steps = 100000; // replace mis-calculation by a safe value - } - - if (dda->rampup_steps > dda->total_steps / 2) - dda->rampup_steps = dda->total_steps / 2; - dda->rampdown_steps = dda->total_steps - dda->rampup_steps; - - #ifdef LOOKAHEAD - dda_join_moves(prev_dda, dda); - #endif - #elif defined ACCELERATION_CLOCK - uint16_t candidate; - - // Total time of the unaccelerated move. - // 1 um/ms = 1 mm/s = 60 mm/min - dda->time_total = distance * (60 / TICK_TIME_MS) / target->F; - - // To avoid overspeeding an axis, movement takes at least as - // long as the slowest axis requires. - candidate = x_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_X; - if (candidate > dda->time_total) - dda->time_total = candidate; - candidate = y_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Y; - if (candidate > dda->time_total) - dda->time_total = candidate; - candidate = z_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_Z; - if (candidate > dda->time_total) - dda->time_total = candidate; - candidate = e_delta_um * (60 / TICK_TIME_MS) / MAXIMUM_FEEDRATE_E; - if (candidate > dda->time_total) - dda->time_total = candidate; - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("time total %u\n"), dda->time_total); - - // Re-calculate speeds, as they might have changed. - dda->F_start = 0; - dda->F_end = 0; - dda->F_max = distance * (60 / TICK_TIME_MS) / dda->time_total; - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("corrected F_max %u\n"), dda->F_max); - - // Time in clock ticks required for acceleration. - dda->time_accel = ((uint32_t)(dda->F_max - dda->F_start)) * - ((uint32_t)(1000 / TICK_TIME_MS)) / - ((uint32_t)(60 * ACCELERATION)); - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("time accel %u\n"), dda->time_accel); - - // Time in clock ticks required for deceleration. - dda->time_decel = ((uint32_t)(dda->F_max - dda->F_end)) * - ((uint32_t)(1000 / TICK_TIME_MS)) / - ((uint32_t)(60 * ACCELERATION)); - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("time decel %u\n"), dda->time_decel); - - // Add time required for acceleration / deceleration. - dda->time_total += dda->time_accel / 2 + dda->time_decel / 2; - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("time total w. accel %u\n"), dda->time_total); - dda->time_decel = dda->time_total - dda->time_decel; - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("time decel2 %u\n"), dda->time_decel); - - // UGLY HACK: to compensate for inaccurate ac- and deceleration - // time calculations, add a margin here: -// dda->time_decel += (dda->time_accel >> 3); -//sersendf_P(PSTR("time decel hacked %u\n"), dda->time_decel); delay_ms(10); - - // This is the ratio between F (in mm/min) and c (in CPU clock ticks) - // and is constant during the entire move, even on curved movements. - // Essentially, it's the step rate of the fastest stepping stepper - // of the entire move. - // For linear movements it's simple: - dda->f_to_c = (distance * 2400L) / dda->total_steps * (F_CPU / 40000) << 8; - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - sersendf_P(PSTR("f_to_c %lu\n"), dda->f_to_c); - - // Initial step delays. As we can't start with zero speed, advance - // all calculations by half a clock tick. - // v = a * t; c = 1 / v; -// Don't forget F_start! - dda->c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * TICK_TIME_MS / 1000UL); - -sersendf_P(PSTR("c_min new %lu\n"), dda->f_to_c / target->F); delay_ms(10); -sersendf_P(PSTR("c_min trad %lu\n"), (move_duration / target->F) << 8); delay_ms(10); - - #elif defined ACCELERATION_TEMPORAL - // TODO: limit speed of individual axes to MAXIMUM_FEEDRATE - // TODO: calculate acceleration/deceleration for each axis - dda->x_step_interval = dda->y_step_interval = \ - dda->z_step_interval = dda->e_step_interval = 0xFFFFFFFF; - if (dda->x_delta) - dda->x_step_interval = move_duration / dda->x_delta; - if (dda->y_delta) - dda->y_step_interval = move_duration / dda->y_delta; - if (dda->z_delta) - dda->z_step_interval = move_duration / dda->z_delta; - if (dda->e_delta) - dda->e_step_interval = move_duration / dda->e_delta; - - dda->axis_to_step = 'x'; - dda->c = dda->x_step_interval; - if (dda->y_step_interval < dda->c) { - dda->axis_to_step = 'y'; - dda->c = dda->y_step_interval; - } - if (dda->z_step_interval < dda->c) { - dda->axis_to_step = 'z'; - dda->c = dda->z_step_interval; - } - if (dda->e_step_interval < dda->c) { - dda->axis_to_step = 'e'; - dda->c = dda->e_step_interval; - } - - dda->c <<= 8; - #else - dda->c = (move_duration / target->F) << 8; - if (dda->c < c_limit) - dda->c = c_limit; - #endif - } /* ! dda->total_steps == 0 */ - - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writestr_P(PSTR("] }\n")); - - // next dda starts where we finish - memcpy(&startpoint, target, sizeof(TARGET)); -} - -/*! Start a prepared DDA - \param *dda pointer to entry in dda_queue to start - - This function actually begins the move described by the passed DDA entry. - - We set direction and enable outputs, and set the timer for the first step from the precalculated value. - - We also mark this DDA as running, so other parts of the firmware know that something is happening - - Called both inside and outside of interrupts. -*/ -void dda_start(DDA *dda) { - // called from interrupt context: keep it simple! - if ( ! dda->nullmove) { - // get ready to go - psu_timeout = 0; - if (dda->z_delta) - z_enable(); - if (dda->endstop_check) - endstops_on(); - - // set direction outputs - x_direction(dda->x_direction); - y_direction(dda->y_direction); - z_direction(dda->z_direction); - e_direction(dda->e_direction); - - #ifdef DC_EXTRUDER - if (dda->e_delta) - heater_set(DC_EXTRUDER, DC_EXTRUDER_PWM); - #endif - - // initialise state variable - move_state.x_counter = move_state.y_counter = move_state.z_counter = \ - move_state.e_counter = -(dda->total_steps >> 1); - memcpy(&move_state.x_steps, &dda->x_delta, sizeof(uint32_t) * 4); - #ifdef ACCELERATION_RAMPING - move_state.step_no = 0; - #endif - #ifdef ACCELERATION_TEMPORAL - move_state.x_time = move_state.y_time = \ - move_state.z_time = move_state.e_time = 0UL; - #endif - - // ensure this dda starts - dda->live = 1; - - // set timeout for first step - #ifdef ACCELERATION_RAMPING - if (dda->c_min > move_state.c) // can be true when look-ahead removed all deceleration steps - setTimer(dda->c_min >> 8); - else - setTimer(move_state.c >> 8); - #else - #ifdef ACCELERATION_CLOCK - move_state.time_current = 0; - move_state.ticks_since_step = 0; - #endif - setTimer(dda->c >> 8); - #endif - } - // else just a speed change, keep dda->live = 0 - - current_position.F = dda->endpoint.F; -} - -/*! STEP - \param *dda the current move - - This is called from our timer interrupt every time a step needs to occur. Keep it as simple as possible! - We first work out which axes need to step, and generate step pulses for them - Then we re-enable global interrupts so serial data reception and other important things can occur while we do some math. - Next, we work out how long until our next step using the selected acceleration algorithm and set the timer. - Then we decide if this was the last step for this move, and if so mark this dda as dead so next timer interrupt we can start a new one. - Finally we de-assert any asserted step pins. -*/ -void dda_step(DDA *dda) { - -#if ! defined ACCELERATION_TEMPORAL - if (move_state.x_steps) { - move_state.x_counter -= dda->x_delta; - if (move_state.x_counter < 0) { - x_step(); - move_state.x_steps--; - move_state.x_counter += dda->total_steps; - } - } -#else // ACCELERATION_TEMPORAL - if (dda->axis_to_step == 'x') { - x_step(); - move_state.x_steps--; - move_state.x_time += dda->x_step_interval; - move_state.all_time = move_state.x_time; - } -#endif - -#if ! defined ACCELERATION_TEMPORAL - if (move_state.y_steps) { - move_state.y_counter -= dda->y_delta; - if (move_state.y_counter < 0) { - y_step(); - move_state.y_steps--; - move_state.y_counter += dda->total_steps; - } - } -#else // ACCELERATION_TEMPORAL - if ((dda->axis_to_step == 'y') && ! endstop_stop) { - y_step(); - move_state.y_steps--; - move_state.y_time += dda->y_step_interval; - move_state.all_time = move_state.y_time; - } -#endif - -#if ! defined ACCELERATION_TEMPORAL - if (move_state.z_steps) { - move_state.z_counter -= dda->z_delta; - if (move_state.z_counter < 0) { - z_step(); - move_state.z_steps--; - move_state.z_counter += dda->total_steps; - } - } -#else // ACCELERATION_TEMPORAL - if (dda->axis_to_step == 'z') { - z_step(); - move_state.z_steps--; - move_state.z_time += dda->z_step_interval; - move_state.all_time = move_state.z_time; - } -#endif - -#if ! defined ACCELERATION_TEMPORAL - if (move_state.e_steps) { - move_state.e_counter -= dda->e_delta; - if (move_state.e_counter < 0) { - e_step(); - move_state.e_steps--; - move_state.e_counter += dda->total_steps; - } - } -#else // ACCELERATION_TEMPORAL - if (dda->axis_to_step == 'e') { - e_step(); - move_state.e_steps--; - move_state.e_time += dda->e_step_interval; - move_state.all_time = move_state.e_time; - } -#endif - - #if defined STEP_INTERRUPT_INTERRUPTIBLE && ! defined ACCELERATION_CLOCK - // Since we have sent steps to all the motors that will be stepping - // and the rest of this function isn't so time critical, this interrupt - // can now be interruptible by other interrupts. - // The step interrupt is disabled before entering dda_step() to ensure - // that we don't step again while computing the below. - sei(); - #endif - - #ifdef ACCELERATION_REPRAP - // linear acceleration magic, courtesy of http://www.embedded.com/columns/technicalinsights/56800129?printable=true - if (dda->accel) { - if ((dda->c > dda->end_c) && (dda->n > 0)) { - uint32_t new_c = dda->c - (dda->c * 2) / dda->n; - if (new_c <= dda->c && new_c > dda->end_c) { - dda->c = new_c; - dda->n += 4; - } - else - dda->c = dda->end_c; - } - else if ((dda->c < dda->end_c) && (dda->n < 0)) { - uint32_t new_c = dda->c + ((dda->c * 2) / -dda->n); - if (new_c >= dda->c && new_c < dda->end_c) { - dda->c = new_c; - dda->n += 4; - } - else - dda->c = dda->end_c; - } - else if (dda->c != dda->end_c) { - dda->c = dda->end_c; - } - // else we are already at target speed - } - #endif - #ifdef ACCELERATION_RAMPING - // - algorithm courtesy of http://www.embedded.com/columns/technicalinsights/56800129?printable=true - // - precalculate ramp lengths instead of counting them, see AVR446 tech note - uint8_t recalc_speed; - - // debug ramping algorithm - //if (move_state.step_no == 0) { - // sersendf_P(PSTR("\r\nc %lu c_min %lu n %d"), dda->c, dda->c_min, move_state.n); - //} - recalc_speed = 0; - if (move_state.step_no < dda->rampup_steps) { - if (move_state.n < 0) // wrong ramp direction - move_state.n = -((int32_t)2) - move_state.n; - recalc_speed = 1; - } - else if (move_state.step_no >= dda->rampdown_steps) { - if (move_state.n > 0) // wrong ramp direction - move_state.n = -((int32_t)2) - move_state.n; - recalc_speed = 1; - } - if (recalc_speed) { - move_state.n += 4; - // be careful of signedness! - move_state.c = (int32_t)move_state.c - ((int32_t)(move_state.c * 2) / (int32_t)move_state.n); - //sersendf_P(PSTR("n:%ld; c:%ld; steps: %ld / %lu\n"), move_state.n, - // move_state.c, move_state.step_no, move_state.y_steps); - } - move_state.step_no++; - - #ifdef ACCELERATION_RAMPING - // This is a hack which deals with movements with an unknown number of - // acceleration steps. dda_create() sets a very high number, then. - if (move_state.c < dda->c_min && - dda->rampup_steps > move_state.step_no + 5) { - dda->rampup_steps = move_state.step_no; - dda->rampdown_steps = dda->total_steps - dda->rampup_steps; - } - #endif - -// Print the number of steps actually needed for ramping up -// Needed for comparing the number with the one calculated in dda_create() -//static char printed = 0; -//if (printed == 0 && dda->c_min >= move_state.c) { -// sersendf_P(PSTR("speedup %lu steps\n"), move_state.step_no); -// printed = 1; -//} -//if (move_state.step_no < 3) printed = 0; - - // debug ramping algorithm - // raise this 10 for higher speeds to avoid flooding the serial line - //if (move_state.step_no % 10 /* 10, 50, 100, ...*/ == 0) - // sersendf_P(PSTR("\r\nc %lu c_min %lu n %ld"), - // move_state.c, dda->c_min, move_state.n); - #endif - - #ifdef ACCELERATION_TEMPORAL - /** How is this ACCELERATION TEMPORAL expected to work? - - All axes work independently of each other, as if they were on four different, synchronized timers. As we have not enough suitable timers, we have to share one for all axes. - - To do this, each axis maintains the time of its last step in move_state.{xyze}_time. This time is updated as the step is done, see early in dda_step(). To find out which axis is the next one to step, the time of each axis' next step is compared to the time of the step just done. Zero means this actually is the axis just stepped, the smallest value > 0 wins. - - One problem undoubtly arising is, steps should sometimes be done at {almost,exactly} the same time. We trust the timer to deal properly with very short or even zero periods. If a step can't be done in time, the timer shall do the step as soon as possible and compensate for the delay later. In turn we promise here to send a maximum of four such short-delays consecutively and to give sufficient time on average. - */ - uint32_t c_candidate; - - dda->c = 0xFFFFFFFF; - if (move_state.x_steps) { - c_candidate = move_state.x_time + dda->x_step_interval - move_state.all_time; - dda->axis_to_step = 'x'; - dda->c = c_candidate; - } - if (move_state.y_steps) { - c_candidate = move_state.y_time + dda->y_step_interval - move_state.all_time; - if (c_candidate < dda->c) { - dda->axis_to_step = 'y'; - dda->c = c_candidate; - } - } - if (move_state.z_steps) { - c_candidate = move_state.z_time + dda->z_step_interval - move_state.all_time; - if (c_candidate < dda->c) { - dda->axis_to_step = 'z'; - dda->c = c_candidate; - } - } - if (move_state.e_steps) { - c_candidate = move_state.e_time + dda->e_step_interval - move_state.all_time; - if (c_candidate < dda->c) { - dda->axis_to_step = 'e'; - dda->c = c_candidate; - } - } - dda->c <<= 8; - #endif - - // If there are no steps left or an endstop stop happened, we have finished. - if ((move_state.x_steps == 0 && move_state.y_steps == 0 && - move_state.z_steps == 0 && move_state.e_steps == 0) - #ifdef ACCELERATION_RAMPING - || (dda->endstop_check && move_state.n == -3) - #endif - ) { - dda->live = 0; - #ifdef ACCELERATION_CLOCK - if (dda->time_total - move_state.time_current > 1) - sersendf_P(PSTR("undershoot by %u ticks\n"), - dda->time_total - move_state.time_current); - #endif - #ifdef LOOKAHEAD - // If look-ahead was using this move, it could have missed our activation: - // make sure the ids do not match. - dda->id--; - #endif - #ifdef DC_EXTRUDER - heater_set(DC_EXTRUDER, 0); - #endif - // z stepper is only enabled while moving - z_disable(); - } - else - psu_timeout = 0; - - #ifdef ACCELERATION_RAMPING - // we don't hit maximum speed exactly with acceleration calculation, so limit it here - // the nice thing about _not_ setting dda->c to dda->c_min is, the move stops at the exact same c as it started, so we have to calculate c only once for the time being - // TODO: set timer only if dda->c has changed - if (dda->c_min > move_state.c) - setTimer(dda->c_min >> 8); - else - setTimer(move_state.c >> 8); - #else - #ifdef ACCELERATION_CLOCK - move_state.ticks_since_step = 0; - #endif - setTimer(dda->c >> 8); - #endif - - // turn off step outputs, hopefully they've been on long enough by now to register with the drivers - // if not, too bad. or insert a (very!) small delay here, or fire up a spare timer or something. - // we also hope that we don't step before the drivers register the low- limit maximum speed if you think this is a problem. - unstep(); -} - -/*! Do regular movement maintenance. - - This should be called pretty often, like once every 1 ot 2 milliseconds. - - Currently, this is checking the endstops. These don't need to be checked on - every single step, so this code can be moved out of the highly time critical - dda_step(). At high precision (slow) searches of the endstop, this function - is called more often than dda_step() anyways. - - In the future, acceleration and arc movement calculations might go here, too. - Updating speed 500 times a second is easily enough for smooth acceleration! -*/ -void dda_clock() { - static volatile uint8_t busy = 0; - DDA *dda; - static DDA *last_dda = NULL; - static uint8_t endstop_stop = 0; ///< Stop due to endstop trigger - - move_state.time_current++; - - dda = queue_current_movement(); - if (dda != last_dda) { - move_state.debounce_count_xmin = move_state.debounce_count_ymin = - move_state.debounce_count_zmin = move_state.debounce_count_xmax = - move_state.debounce_count_ymax = move_state.debounce_count_zmax = 0; - endstop_stop = 0; - last_dda = dda; - } - - if (dda == NULL) - return; - - // Lengthy calculations ahead! - // Make sure we didn't re-enter, then allow nested interrupts. - if (busy) { - if (DEBUG_DDA && (debug_flags & DEBUG_DDA)) - serial_writechar('B'); - return; - } - busy = 1; - sei(); - - // Caution: we mangle step counters here without locking interrupts. This - // means, we trust dda isn't changed behind our back, which could - // in principle (but rarely) happen if endstops are checked not as - // endstop search, but as part of normal operations. - if (endstop_stop == 0) { - #if defined X_MIN_PIN || defined X_MAX_PIN - if (dda->endstop_check & 0x1) { - #if defined X_MIN_PIN - if (x_min() == dda->endstop_stop_cond) - move_state.debounce_count_xmin++; - else - move_state.debounce_count_xmin = 0; - #endif - #if defined X_MAX_PIN - if (x_max() == dda->endstop_stop_cond) - move_state.debounce_count_xmax++; - else - move_state.debounce_count_xmax = 0; - #endif - endstop_stop = move_state.debounce_count_xmin >= ENDSTOP_STEPS || - move_state.debounce_count_xmax >= ENDSTOP_STEPS; - } - #endif - - #if defined Y_MIN_PIN || defined Y_MAX_PIN - if (dda->endstop_check & 0x2) { - #if defined Y_MIN_PIN - if (y_min() == dda->endstop_stop_cond) - move_state.debounce_count_ymin++; - else - move_state.debounce_count_ymin = 0; - #endif - #if defined Y_MAX_PIN - if (y_max() == dda->endstop_stop_cond) - move_state.debounce_count_ymax++; - else - move_state.debounce_count_ymax = 0; - #endif - endstop_stop = move_state.debounce_count_ymin >= ENDSTOP_STEPS || - move_state.debounce_count_ymax >= ENDSTOP_STEPS; - } - #endif - - #if defined Z_MIN_PIN || defined Z_MAX_PIN - if (dda->endstop_check & 0x4) { - #if defined Z_MIN_PIN - if (z_min() == dda->endstop_stop_cond) - move_state.debounce_count_zmin++; - else - move_state.debounce_count_zmin = 0; - #endif - #if defined Z_MAX_PIN - if (z_max() == dda->endstop_stop_cond) - move_state.debounce_count_zmax++; - else - move_state.debounce_count_zmax = 0; - #endif - endstop_stop = move_state.debounce_count_zmin >= ENDSTOP_STEPS || - move_state.debounce_count_zmax >= ENDSTOP_STEPS; - } - #endif - - // If an endstop is definitely triggered, stop the movement. - if (endstop_stop) { - #ifdef ACCELERATION_RAMPING - // For always smooth operations, don't halt apruptly, - // but start deceleration here. - ATOMIC_START - dda->rampdown_steps = move_state.step_no; - dda->rampup_steps = 0; // in case we're still accelerating - ATOMIC_END - #else - dda->live = 0; - #endif - - endstops_off(); - } - } /* if (endstop_stop == 0) */ - - #ifdef ACCELERATION_CLOCK - uint32_t new_c = 0; - static uint8_t plateau_done = 0; - - // Overtime? - if (move_state.time_current > dda->time_total) { - // Keep it short to have at least a chance to get it sent. - #warning Das hier hört nicht auf. - //serial_writestr_P(PSTR("ot")); - move_state.time_current = dda->time_total; - } - // Acceleration time. - else if (move_state.time_current < dda->time_accel) { - // v = a * t; c = 1 / v; - new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * (uint32_t)move_state.time_current * TICK_TIME_MS / 1000UL); - plateau_done = 0; -serial_writechar('a'); - } - else if (move_state.time_current > dda->time_decel) { - uint32_t dt = (uint32_t)dda->time_total - (uint32_t)move_state.time_current; - - if (dt < 1) // we undershot *sigh* - dt = 1; - // v = a * t; c = 1 / v; - new_c = dda->f_to_c / ((uint32_t)ACCELERATION * 60UL * dt * TICK_TIME_MS / 1000UL); -serial_writechar('d'); - plateau_done = 0; - - } - // Plateau time. - else if (plateau_done == 0) { - new_c = dda->f_to_c / dda->F_max; - plateau_done = 1; -serial_writechar('r'); - } - else -serial_writechar('.'); - - if (new_c) { - ATOMIC_START - dda->c = new_c; - ATOMIC_END - } - - // Set up or readjust the timer if actual steps happen too slowly. dda_step() - // resets ticks_since_step to zero, while we increment it here, so we have an - // idea on how much time is gone since the last actual step. - // 300 = minimum time setTimer requires. -if (dda->time_total == move_state.time_current) -sersendf_P(PSTR("overshoot by %lu steps\n"), move_state.x_steps); - if (move_state.ticks_since_step) { - if ((dda->c >> 8) < ((uint32_t)move_state.ticks_since_step * TICK_TIME) + 300UL) { - // We're too late already, go as quick as possbile. - setTimer(300UL); -serial_writechar('-'); - } - else { - // TODO: we ignore the time taken until we get here. - setTimer((dda->c >> 8) - ((uint32_t)move_state.ticks_since_step * TICK_TIME)); -serial_writechar('+'); - } - } - sei(); // setTimer locks interrupts - move_state.ticks_since_step++; - #endif - - cli(); // Compensate sei() above. - busy = 0; -} - -/// update global current_position struct -void update_current_position() { - DDA *dda = &movebuffer[mb_tail]; - - if (queue_empty()) { - current_position.X = startpoint.X; - current_position.Y = startpoint.Y; - current_position.Z = startpoint.Z; - current_position.E = startpoint.E; - } - else if (dda->live) { - if (dda->x_direction) - // (STEPS_PER_M_X / 1000) is a bit inaccurate for low STEPS_PER_M numbers - current_position.X = dda->endpoint.X - - // should be: move_state.x_steps * 1000000 / STEPS_PER_M_X) - // but x_steps can be like 1000000 already, so we'd overflow - move_state.x_steps * 1000 / ((STEPS_PER_M_X + 500) / 1000); - else - current_position.X = dda->endpoint.X + - move_state.x_steps * 1000 / ((STEPS_PER_M_X + 500) / 1000); - - if (dda->y_direction) - current_position.Y = dda->endpoint.Y - - move_state.y_steps * 1000 / ((STEPS_PER_M_Y + 500) / 1000); - else - current_position.Y = dda->endpoint.Y + - move_state.y_steps * 1000 / ((STEPS_PER_M_Y + 500) / 1000); - - if (dda->z_direction) - current_position.Z = dda->endpoint.Z - - move_state.z_steps * 1000 / ((STEPS_PER_M_Z + 500) / 1000); - else - current_position.Z = dda->endpoint.Z + - move_state.z_steps * 1000 / ((STEPS_PER_M_Z + 500) / 1000); - - if (dda->endpoint.e_relative) { - current_position.E = move_state.e_steps * 1000 / ((STEPS_PER_M_E + 500) / 1000); - } - else { - if (dda->e_direction) - current_position.E = dda->endpoint.E - - move_state.e_steps * 1000 / ((STEPS_PER_M_E + 500) / 1000); - else - current_position.E = dda->endpoint.E + - move_state.e_steps * 1000 / ((STEPS_PER_M_E + 500) / 1000); - } - - // current_position.F is updated in dda_start() - } -} diff --git a/attic/accel_clock/dda.h b/attic/accel_clock/dda.h deleted file mode 100644 index eea60a0..0000000 --- a/attic/accel_clock/dda.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef _DDA_H -#define _DDA_H - -#include - -#include "config_wrapper.h" - -#ifdef ACCELERATION_REPRAP - #ifdef ACCELERATION_RAMPING - #error Cant use ACCELERATION_REPRAP and ACCELERATION_RAMPING together. - #endif -#endif - -/* - types -*/ - -// Enum to denote an axis -enum axis_e { X, Y, Z, E }; - -/** - \struct TARGET - \brief target is simply a point in space/time - - X, Y, Z and E are in micrometers unless explcitely stated. F is in mm/min. -*/ -typedef struct { -// TODO TODO: We should really make up a loop for all axes. -// Think of what happens when a sixth axis (multi colour extruder) -// appears? - int32_t X; - int32_t Y; - int32_t Z; - int32_t E; - uint32_t F; - - uint8_t e_relative :1; ///< bool: e axis relative? Overrides all_relative -} TARGET; - -/** - \struct VECTOR4D - \brief 4 dimensional vector used to describe the difference between moves. - - Units are in micrometers and usually based off 'TARGET'. -*/ -typedef struct { - int32_t X; - int32_t Y; - int32_t Z; - int32_t E; -} VECTOR4D; - -/** - \struct MOVE_STATE - \brief this struct is made for tracking the current state of the movement - - Parts of this struct are initialised only once per reboot, so make sure dda_step() leaves them with a value compatible to begin a new movement at the end of the movement. Other parts are filled in by dda_start(). -*/ -typedef struct { - // bresenham counters - int32_t x_counter; ///< counter for total_steps vs this axis - int32_t y_counter; ///< counter for total_steps vs this axis - int32_t z_counter; ///< counter for total_steps vs this axis - int32_t e_counter; ///< counter for total_steps vs this axis - - // step counters - uint32_t x_steps; ///< number of steps on X axis - uint32_t y_steps; ///< number of steps on Y axis - uint32_t z_steps; ///< number of steps on Z axis - uint32_t e_steps; ///< number of steps on E axis - - #ifdef ACCELERATION_RAMPING - /// counts actual steps done - uint32_t step_no; - /// time until next step - uint32_t c; - /// tracking variable - int32_t n; - #endif - #ifdef ACCELERATION_CLOCK - uint16_t time_current; - uint8_t ticks_since_step; - #endif - #ifdef ACCELERATION_TEMPORAL - uint32_t x_time; ///< time of the last x step - uint32_t y_time; ///< time of the last y step - uint32_t z_time; ///< time of the last z step - uint32_t e_time; ///< time of the last e step - uint32_t all_time; ///< time of the last step of any axis - #endif - - /// Endstop debouncing - uint8_t debounce_count_xmin, debounce_count_ymin, debounce_count_zmin; - uint8_t debounce_count_xmax, debounce_count_ymax, debounce_count_zmax; -} MOVE_STATE; - -/** - \struct DDA - \brief this is a digital differential analyser data struct - - This struct holds all the details of an individual multi-axis move, including pre-calculated acceleration data. - This struct is filled in by dda_create(), called from enqueue(), called mostly from gcode_process() and from a few other places too (eg \file homing.c) -*/ -typedef struct { - /// this is where we should finish - TARGET endpoint; - - union { - struct { - // status fields - uint8_t nullmove :1; ///< bool: no axes move, maybe we wait for temperatures or change speed - uint8_t live :1; ///< bool: this DDA is running and still has steps to do - #ifdef ACCELERATION_REPRAP - uint8_t accel :1; ///< bool: speed changes during this move, run accel code - #endif - - // wait for temperature to stabilise flag - uint8_t waitfor_temp :1; ///< bool: wait for temperatures to reach their set values - - // directions - uint8_t x_direction :1; ///< direction flag for X axis - uint8_t y_direction :1; ///< direction flag for Y axis - uint8_t z_direction :1; ///< direction flag for Z axis - uint8_t e_direction :1; ///< direction flag for E axis - }; - uint8_t allflags; ///< used for clearing all flags - }; - - // distances - uint32_t x_delta; ///< number of steps on X axis - uint32_t y_delta; ///< number of steps on Y axis - uint32_t z_delta; ///< number of steps on Z axis - uint32_t e_delta; ///< number of steps on E axis - - /// total number of steps: set to \f$\max(\Delta x, \Delta y, \Delta z, \Delta e)\f$ - uint32_t total_steps; - - uint32_t c; ///< time until next step, 24.8 fixed point - - #ifdef ACCELERATION_REPRAP - uint32_t end_c; ///< time between 2nd last step and last step - int32_t n; ///< precalculated step time offset variable. At every step we calculate \f$c = c - (2 c / n)\f$; \f$n+=4\f$. See http://www.embedded.com/columns/technicalinsights/56800129?printable=true for full description - #endif - #ifdef ACCELERATION_RAMPING - /// number of steps accelerating - uint32_t rampup_steps; - /// number of last step before decelerating - uint32_t rampdown_steps; - /// 24.8 fixed point timer value, maximum speed - uint32_t c_min; - #ifdef LOOKAHEAD - // With the look-ahead functionality, it is possible to retain physical - // movement between G1 moves. These variables keep track of the entry and - // exit speeds between moves. - uint32_t F_start; - uint32_t F_end; - // Displacement vector, in um, based between the difference of the starting - // point and the target. Required to obtain the jerk between 2 moves. - // Note: x_delta and co are in steps, not um. - VECTOR4D delta; - // Number the moves to be able to test at the end of lookahead if the moves - // are the same. Note: we do not need a lot of granularity here: more than - // MOVEBUFFER_SIZE is already enough. - uint8_t id; - #endif - #endif - #ifdef ACCELERATION_CLOCK - uint16_t F_start; - uint16_t F_end; - uint16_t F_max; - uint16_t time_accel; ///< in clock ticks (1ms or 2ms) - uint16_t time_decel; ///< in clock ticks (1ms or 2ms) - uint16_t time_total; ///< in clock ticks (1ms or 2ms) - uint32_t f_to_c; - #endif - #ifdef ACCELERATION_TEMPORAL - uint32_t x_step_interval; ///< time between steps on X axis - uint32_t y_step_interval; ///< time between steps on Y axis - uint32_t z_step_interval; ///< time between steps on Z axis - uint32_t e_step_interval; ///< time between steps on E axis - uint8_t axis_to_step; ///< axis to be stepped on the next interrupt - #endif - - /// Endstop homing - uint8_t endstop_check; ///< Do we need to check endstops? 0x1=Check X, 0x2=Check Y, 0x4=Check Z - uint8_t endstop_stop_cond; ///< Endstop condition on which to stop motion: 0=Stop on detrigger, 1=Stop on trigger -} DDA; - -/* - variables -*/ - -/// startpoint holds the endpoint of the most recently created DDA, so we know where the next one created starts. could also be called last_endpoint -extern TARGET startpoint; - -/// the same as above, counted in motor steps -extern TARGET startpoint_steps; - -/// current_position holds the machine's current position. this is only updated when we step, or when G92 (set home) is received. -extern TARGET current_position; - -/* - methods -*/ - -// initialize dda structures -void dda_init(void); - -// distribute a new startpoint -void dda_new_startpoint(void); - -// create a DDA -void dda_create(DDA *dda, TARGET *target, DDA *prev_dda); - -// start a created DDA (called from timer interrupt) -void dda_start(DDA *dda) __attribute__ ((hot)); - -// DDA takes one step (called from timer interrupt) -void dda_step(DDA *dda) __attribute__ ((hot)); - -// regular movement maintenance -void dda_clock(void); - -// update current_position -void update_current_position(void); - -#endif /* _DDA_H */