yarf 0.1
Yet Another RepRap Firmware
src/movement/block_handler.c
Go to the documentation of this file.
00001 /*
00002  * block_handler.c
00003  *
00004  * Copyright 2011 Pieter Agten
00005  *
00006  * This file is part of Yarf.
00007  *
00008  * Yarf is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 3 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Yarf is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Yarf.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00030 #include "block_handler.h"
00031 
00032 #include "yarf.h"
00033 #include "movement/planner_queue.h"
00034 #include "hardware/steppers.h"
00035 #include "hardware/endstops.h"
00036 #include "hardware/usart.h"
00037 #include "scheduling/realtime_timer.h"
00038 #include "util/math.h"
00039 #include "advance.h"
00040 
00041 #include <stdlib.h>
00042 #include <util/delay.h>
00043 #include <util/atomic.h>
00044 
00049 #define BLOCK_HANDLER_START_DELAY_TICKS 1L
00050 
00054 static bool handler_running;
00055 
00061 static realtime_task_t handler_task;
00062 
00063 
00067 static block_t *b;
00068 
00069 
00074 static steps_t counter[NUM_AXES]; 
00075 
00076 
00077 #if ADVANCE_ALGORITHM
00078 
00082 static volatile int32_t e_steps;
00083 
00091 static int32_t previous_advance;
00092 
00101 static uint8_t extruder_tick_state;
00102 #endif
00103 
00108 static void
00109 block_progress_init(void)
00110 {
00111   int axis;
00112   for(axis = 0; axis < NUM_AXES; ++axis) {
00113     counter[axis] = -(b->nb_steps/2);
00114   }
00115 }
00116 
00122 static inline void
00123 enable_steppers(void)
00124 {
00125   if (b->steps[X_AXIS] != 0) {
00126     stepper_enable_x();
00127   }
00128   if (b->steps[Y_AXIS] != 0) {
00129     stepper_enable_y();
00130   }
00131   if (b->steps[Z_AXIS] != 0) {
00132     stepper_enable_z();
00133   }
00134   if (b->steps[E_AXIS] != 0) {
00135     stepper_enable_e();
00136   }
00137 }
00138 
00143 static inline void
00144 disable_steppers(void)
00145 {
00146 #if !STEPPER_HOLD_X
00147   stepper_disable_x();
00148 #endif
00149 #if !STEPPER_HOLD_Y
00150   stepper_disable_y();
00151 #endif
00152 #if !STEPPER_HOLD_Z
00153   stepper_disable_z();
00154 #endif
00155 #if !STEPPER_HOLD_E && !ADVANCE_ALGORITHM
00156   stepper_disable_e();
00157 #endif
00158 }
00159 
00163 static inline void
00164 block_finished(void)
00165 {
00166   b = NULL;
00167 
00168   /* Remove the block from the tail of the queue */
00169   plan_q_discard_tail();
00170   
00171   /* Disable the stepper motors that need not be held */
00172   disable_steppers();
00173 }
00174 
00178 static inline void
00179 cancel_block(void)
00180 {
00181   block_finished();
00182   rttimer_schedule_ticks(&handler_task,1);
00183 }
00184 
00185 
00186 #if ADVANCE_ALGORITHM
00187 //TODO: enable/disable interrupt
00188 
00197 static inline void
00198 block_handler_extruder_tick(void)
00199 {
00200   /* Set the timer 1 A top value */
00201   OCR1A += EXTRUDER_TIMER_TICKS;
00202   TIFR1 |= _BV(OCF1A);
00203 
00204   /* Check the USART0 receive buffer, to prevent data overrun */
00205   usart0_try_read_character();
00206 
00207   if (extruder_tick_state == 0) {
00208     extruder_tick_state = 1;
00209     stepper_e_step_low();
00210   } else {
00211     extruder_tick_state = 0;
00212       if (e_steps == 0) {
00213         return;
00214       }
00215       
00216       if (e_steps < 0) {
00217         stepper_e_dir_neg();
00218         e_steps += 1;
00219       } else if (e_steps > 0) {
00220         stepper_e_dir_pos();
00221         e_steps -= 1;
00222       }
00223     stepper_e_step_high();
00224   }  
00225 }
00226 
00231 ISR(TIMER1_COMPA_vect, ISR_BLOCK)
00232 {
00233   block_handler_extruder_tick();
00234 }
00235 
00236 #endif
00237 
00238 
00243 static inline void
00244 update_advance(void)
00245 {
00246 #if ADVANCE_ALGORITHM
00247   b->advance = advance_get_value(b);
00248 #endif
00249 }
00250 
00268 static void
00269 block_handler_run(void)
00270 {
00271   if (b == NULL) {
00272     /* Get new block to execute from the planning queue */
00273     b = plan_q_tail();
00274     if (b == NULL) {
00275       /* No blocks to be executed */
00276       handler_running = false;
00277       return;
00278     } else {
00279       block_progress_init();
00280       enable_steppers();
00281     }
00282   }
00283 
00284 
00285   /* Make sure all the stepper inputs are low */
00286   stepper_x_step_low();
00287   stepper_y_step_low();
00288   stepper_z_step_low();
00289 #if !ADVANCE_ALGORITHM
00290   stepper_e_step_low();
00291 #endif
00292 
00293   
00294   /* Setup the steppers' direction pins and check the endstops */
00295   uint8_t collisions = 0;
00296   if (b->steps[X_AXIS] < 0) {
00297     stepper_x_dir_neg();
00298     if (endstop_x_min()) {
00299       collisions |= _BV(X_AXIS_NEG);
00300     }
00301   } else if (b->steps[X_AXIS] > 0) {
00302     stepper_x_dir_pos();
00303     if (endstop_x_max()) {
00304       collisions |= _BV(X_AXIS_POS);
00305     }
00306   }
00307   if (b->steps[Y_AXIS] < 0) {
00308     stepper_y_dir_neg();
00309     if (endstop_y_min()) {
00310       collisions |= _BV(Y_AXIS_NEG);
00311     }
00312   } else if (b->steps[Y_AXIS] > 0) {
00313     stepper_y_dir_pos();
00314     if (endstop_y_max()) {
00315       collisions |= _BV(Y_AXIS_POS);
00316     }
00317   }
00318   if (b->steps[Z_AXIS] < 0) {
00319     stepper_z_dir_neg();
00320     if (endstop_z_min()) {
00321       collisions |= _BV(Z_AXIS_NEG);
00322     }
00323   } else if (b->steps[Z_AXIS] > 0) {
00324     stepper_z_dir_pos();
00325     if (endstop_z_max()) {
00326       collisions |= _BV(Z_AXIS_POS);
00327     }
00328   }
00329 #if !ADVANCE_ALGORITHM
00330   if (b->steps[E_AXIS] < 0) {
00331     stepper_e_dir_neg();
00332   } else {
00333     stepper_e_dir_pos();
00334   }
00335 #endif
00336 
00337   if (collisions) {
00338     b->collision_handler(collisions);
00339     cancel_block();
00340     return;
00341   }
00342 
00343   /* Step all the steppers that need to step */
00344   counter[X_AXIS] += labs(b->steps[X_AXIS]);
00345   if (counter[X_AXIS] > 0) {
00346     counter[X_AXIS] -= b->nb_steps;
00347     stepper_x_step_high();
00348   }
00349   counter[Y_AXIS] += labs(b->steps[Y_AXIS]);
00350   if (counter[Y_AXIS] > 0) {
00351     counter[Y_AXIS] -= b->nb_steps;
00352     stepper_y_step_high();
00353   }
00354   counter[Z_AXIS] += labs(b->steps[Z_AXIS]);
00355   if (counter[Z_AXIS] > 0) {
00356     counter[Z_AXIS] -= b->nb_steps;
00357     stepper_z_step_high();
00358   }
00359 #if !ADVANCE_ALGORITHM
00360   counter[E_AXIS] += labs(b->steps[E_AXIS]);
00361   if (counter[E_AXIS] > 0) {
00362     counter[E_AXIS] -= b->nb_steps;
00363     stepper_e_step_high();
00364   }
00365 #else
00366   /* Calculate E steps to take */
00367   counter[E_AXIS] += labs(b->steps[E_AXIS]);
00368   if (counter[E_AXIS] > 0) {
00369     counter[E_AXIS] -= b->nb_steps;
00370     if (b->steps[E_AXIS] < 0) {
00371       e_steps -= 1;
00372     } else {
00373       e_steps += 1;
00374     }
00375   }    
00376   /* Do advance steps */
00377   e_steps += (b->advance - previous_advance);
00378   previous_advance = b->advance;
00379   block_handler_extruder_tick();
00380 #endif
00381 
00382 
00383 
00384   /* Reschedule the timer */
00385   b->nb_steps_completed += 1;
00386   fxp16u16_t diff = fxp16u16_div_uint16(2*b->timer_ticks, b->acceleration_step);
00387   if (b->nb_steps_completed < b->acceleration_end) {
00388     /* We're in the acceleration slope */
00389     if (b->timer_ticks - b->plateau_timer_ticks > diff) { // overflow detection
00390       b->timer_ticks -= diff;
00391     } else {
00392       b->timer_ticks = b->plateau_timer_ticks;
00393     }
00394 
00395     b->acceleration_step += 4;
00396     update_advance();
00397   } else if (b->nb_steps_completed >= b->deceleration_start) {
00398     /* We're in the deceleration slope */
00399     if (b->timer_ticks < b->exit_timer_ticks &&
00400         b->exit_timer_ticks - b->timer_ticks > diff) { // overflow detection
00401       b->timer_ticks += diff; 
00402     } else {
00403       b->timer_ticks = b->exit_timer_ticks;
00404     }
00405 
00406     if (b->acceleration_step > 4) {
00407       b->acceleration_step -= 4;
00408     } else {
00409       b->acceleration_step = 1;
00410     }
00411     update_advance();
00412   } else {
00413     b->timer_ticks = b->plateau_timer_ticks;
00414   }
00415   rttimer_schedule_ticks(&handler_task, fxp16u16_to_uint16(b->timer_ticks));
00416 
00417 
00418   /* Check if we're done with this block */
00419   if (b->nb_steps_completed >= b->nb_steps) {
00420     block_finished();
00421   }
00422 }
00423 
00424 
00425 
00426 void
00427 block_handler_init(void)
00428 {
00429   rttimer_init();
00430 
00431   b = NULL;
00432   handler_running = false;
00433   handler_task.f = block_handler_run;
00434 
00435 #if ADVANCE_ALGORITHM
00436   e_steps = 0;
00437   previous_advance = 0;
00438   extruder_tick_state = 0;
00439 #endif
00440 }
00441 
00442 void 
00443 block_handler_start(void)
00444 {
00445   if (! handler_running) {
00446     handler_running = true;
00447     rttimer_schedule_ticks(&handler_task, BLOCK_HANDLER_START_DELAY_TICKS);
00448   }
00449 }
00450 
00451 void
00452 block_handler_pause(void)
00453 {
00454   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00455     if (handler_running) {
00456       rttimer_cancel();
00457       handler_running = false;    
00458     }
00459   }
00460 }
00461 
00462 void
00463 block_handler_stop(void)
00464 {
00465   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
00466     if (handler_running) {
00467       rttimer_cancel();
00468       if (b != NULL) {
00469         block_finished();
00470       }
00471       handler_running = false;    
00472     }
00473   }
00474 }
00475 
00476 bool
00477 block_handler_running(void)
00478 {
00479   return handler_running;
00480 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines