refactors
[clinton/Smoothieware.git] / src / libs / StepTicker.cpp
index 5963e01..54c4406 100644 (file)
 #include "StepperMotor.h"
 #include "StreamOutputPool.h"
 #include "Block.h"
+#include "Conveyor.h"
 
 #include "system_LPC17xx.h" // mbed.h lib
 #include <math.h>
 #include <mri.h>
 
 #ifdef STEPTICKER_DEBUG_PIN
+// debug pins, only used if defined in src/makefile
 #include "gpio.h"
-extern GPIO stepticker_debug_pin;
+GPIO stepticker_debug_pin(STEPTICKER_DEBUG_PIN);
+#define SET_STEPTICKER_DEBUG_PIN(n) {if(n) stepticker_debug_pin.set(); else stepticker_debug_pin.clear(); }
+#else
+#define SET_STEPTICKER_DEBUG_PIN(n)
 #endif
 
 StepTicker *StepTicker::instance;
@@ -47,7 +52,14 @@ StepTicker::StepTicker()
     this->unstep.reset();
     this->num_motors = 0;
 
-    this->move_issued = false;
+    this->running = false;
+    this->current_block = nullptr;
+
+    #ifdef STEPTICKER_DEBUG_PIN
+    // setup debug pin if defined
+    stepticker_debug_pin.output();
+    stepticker_debug_pin= 0;
+    #endif
 }
 
 StepTicker::~StepTicker()
@@ -115,72 +127,84 @@ void StepTicker::handle_finish (void)
     if(finished_fnc) finished_fnc();
 }
 
-
 // step clock
 void StepTicker::step_tick (void)
 {
     static uint32_t current_tick = 0;
 
-    if(!move_issued){
-        if(jobq.empty()) return; // if nothing has been setup we ignore the ticks
-        // get next job, and copy data
-        Block *b= nullptr;
-        jobq.get(b);
-        copy_block(b);
-    }
+    //SET_STEPTICKER_DEBUG_PIN(running ? 1 : 0);
 
-    current_tick++; // count number of ticks
+    // if nothing has been setup we ignore the ticks
+    if(!running){
+        // check if anything new available
+        if(THECONVEYOR->get_next_block(&current_block)) { // returns false if no new block is available
+            running= start_next_block(); // returns true if there is at least one motor with steps to issue
+            if(!running) return;
+        }else{
+            return;
+        }
+    }
 
-    bool still_moving = false;
+    if(THEKERNEL->is_halted()) {
+        running= false;
+        return;
+    }
 
+    bool still_moving= false;
     // foreach motor, if it is active see if time to issue a step to that motor
     for (uint8_t m = 0; m < num_motors; m++) {
-        if(tick_info[m].steps_to_move == 0) continue; // not active
+        if(current_block->tick_info[m].steps_to_move == 0) continue; // not active
 
-        still_moving = true;
-        tick_info[m].steps_per_tick += tick_info[m].acceleration_change;
+        current_block->tick_info[m].steps_per_tick += current_block->tick_info[m].acceleration_change;
 
-        if(current_tick == tick_info[m].next_accel_event) {
-            if(current_tick == block_info.accelerate_until) { // We are done accelerating, deceleration becomes 0 : plateau
-                tick_info[m].acceleration_change = 0;
-                if(block_info.decelerate_after < block_info.total_move_ticks) {
-                    tick_info[m].next_accel_event = block_info.decelerate_after;
-                    if(current_tick != block_info.decelerate_after) { // We are plateauing
+        if(current_tick == current_block->tick_info[m].next_accel_event) {
+            if(current_tick == current_block->accelerate_until) { // We are done accelerating, deceleration becomes 0 : plateau
+                current_block->tick_info[m].acceleration_change = 0;
+                if(current_block->decelerate_after < current_block->total_move_ticks) {
+                    current_block->tick_info[m].next_accel_event = current_block->decelerate_after;
+                    if(current_tick != current_block->decelerate_after) { // We are plateauing
                         // steps/sec / tick frequency to get steps per tick
-                        tick_info[m].steps_per_tick = tick_info[m].plateau_rate;
+                        current_block->tick_info[m].steps_per_tick = current_block->tick_info[m].plateau_rate;
                     }
                 }
             }
 
-            if(current_tick == block_info.decelerate_after) { // We start decelerating
-                tick_info[m].acceleration_change = tick_info[m].deceleration_change;
+            if(current_tick == current_block->decelerate_after) { // We start decelerating
+                current_block->tick_info[m].acceleration_change = current_block->tick_info[m].deceleration_change;
             }
         }
 
         // protect against rounding errors and such
-        if(tick_info[m].steps_per_tick <= 0) {
-            tick_info[m].counter = (1<<30); // we complete this step
-            tick_info[m].steps_per_tick = 0;
+        if(current_block->tick_info[m].steps_per_tick <= 0) {
+            current_block->tick_info[m].counter = STEPTICKER_FPSCALE; // we force completion this step by setting to 1.0
+            current_block->tick_info[m].steps_per_tick = 0;
         }
 
-        tick_info[m].counter += tick_info[m].steps_per_tick;
+        current_block->tick_info[m].counter += current_block->tick_info[m].steps_per_tick;
 
-        if(tick_info[m].counter >= (1<<30)) { // > 1.0 step time
-            tick_info[m].counter -= (1<<30); // -= 1.0F;
-            ++tick_info[m].step_count;
+        if(current_block->tick_info[m].counter >= STEPTICKER_FPSCALE) { // >= 1.0 step time
+            current_block->tick_info[m].counter -= STEPTICKER_FPSCALE; // -= 1.0F;
+            ++current_block->tick_info[m].step_count;
 
             // step the motor
-            motor[m]->step();
+            bool ismoving= motor[m]->step(); // returns false if the moving flag was set to false externally (probes, endstops etc)
             // we stepped so schedule an unstep
             unstep.set(m);
 
-            if(tick_info[m].step_count == tick_info[m].steps_to_move) {
+            if(!ismoving || current_block->tick_info[m].step_count == current_block->tick_info[m].steps_to_move) {
                 // done
-                tick_info[m].steps_to_move = 0;
+                current_block->tick_info[m].steps_to_move = 0;
+                motor[m]->moving= false; // let motor know it is no longer moving
             }
         }
+
+        // see if any motors are still moving after this tick
+        if(motor[m]->moving) still_moving= true;
     }
 
+    // do this after so we start at tick 0
+    current_tick++; // count number of ticks
+
     // We may have set a pin on in this tick, now we reset the timer to set it off
     // Note there could be a race here if we run another tick before the unsteps have happened,
     // right now it takes about 3-4us but if the unstep were near 10uS or greater it would be an issue
@@ -190,83 +214,60 @@ void StepTicker::step_tick (void)
         LPC_TIM1->TCR = 1;
     }
 
+
+    // see if any motors are still moving
     if(!still_moving) {
+        SET_STEPTICKER_DEBUG_PIN(0);
+
         // all moves finished
         current_tick = 0;
 
-        // get next static block and tick info from next block
+        // get next block
         // do it here so there is no delay in ticks
-        if(!jobq.empty()) {
-            #ifdef STEPTICKER_DEBUG_PIN
-            stepticker_debug_pin = 1;
-            #endif
-
-            // get next job, and copy data
-            Block *b= nullptr;
-            jobq.get(b);
-            copy_block(b);
-
-            #ifdef STEPTICKER_DEBUG_PIN
-            stepticker_debug_pin = 0;
-            #endif
-
-        } else {
-            move_issued = false; // nothing to do as no more blocks
+        THECONVEYOR->block_finished();
+
+        if(THECONVEYOR->get_next_block(&current_block)) { // returns false if no new block is available
+            running= start_next_block(); // returns true if there is at least one motor with steps to issue
+
+        }else{
+            current_block= nullptr;
+            running= false;
         }
 
         // all moves finished
         // we delegate the slow stuff to the pendsv handler which will run as soon as this interrupt exits
         //NVIC_SetPendingIRQ(PendSV_IRQn); this doesn't work
-        SCB->ICSR = 0x10000000; // SCB_ICSR_PENDSVSET_Msk;
+        //SCB->ICSR = 0x10000000; // SCB_ICSR_PENDSVSET_Msk;
     }
 }
 
-// called in ISR if running, else can be called from anything to start
-void StepTicker::copy_block(Block *block)
+// only called from the step tick ISR (single consumer)
+bool StepTicker::start_next_block()
 {
-    stepticker_debug_pin = 1;
-    block_info.accelerate_until = block->accelerate_until;
-    block_info.decelerate_after = block->decelerate_after;
-    block_info.total_move_ticks = block->total_move_ticks;
+    if(current_block == nullptr) return false;
 
-    float inv = 1.0F / block->steps_event_count;
+    bool ok= false;
+    // need to prepare each active motor
     for (uint8_t m = 0; m < num_motors; m++) {
-        uint32_t steps = block->steps[m];
-        tick_info[m].steps_to_move = steps;
-        if(steps == 0) continue;
+        if(current_block->tick_info[m].steps_to_move == 0) continue;
 
+        ok= true; // mark at least one motor is moving
         // set direction bit here
-        motor[m]->set_direction(block->direction_bits[m]);
-
-        float aratio = inv * steps;
-        tick_info[m].steps_per_tick = floorf(((block->initial_rate * aratio) / frequency) * (1<<30)); // steps/sec / tick frequency to get steps per tick in 2.30 fixed point
-        tick_info[m].counter = 0; // 2.30 fixed point
-        tick_info[m].step_count = 0;
-        tick_info[m].next_accel_event = block->total_move_ticks + 1;
-
-        float acceleration_change = 0;
-        if(block->accelerate_until != 0) { // If the next accel event is the end of accel
-            tick_info[m].next_accel_event = block->accelerate_until;
-            acceleration_change = block->acceleration_per_tick;
-
-        } else if(block->decelerate_after == 0 /*&& block->accelerate_until == 0*/) {
-            // we start off decelerating
-            acceleration_change = -block->deceleration_per_tick;
-
-        } else if(block->decelerate_after != block->total_move_ticks /*&& block->accelerate_until == 0*/) {
-            // If the next event is the start of decel ( don't set this if the next accel event is accel end )
-            tick_info[m].next_accel_event = block->decelerate_after;
-        }
+        // NOTE this would be at least 10us before first step pulse.
+        // TODO does this need to be done sooner, if so how without delaying next tick
+        motor[m]->set_direction(current_block->direction_bits[m]);
+        motor[m]->moving= true; // also let motor know it is moving now
+    }
 
-        // convert to fixed point after scaling
-        tick_info[m].acceleration_change= floorf((acceleration_change * aratio) * (1<<30));
-        tick_info[m].deceleration_change= -floorf((block->deceleration_per_tick * aratio) * (1<<30));
-        tick_info[m].plateau_rate= floorf(((block->maximum_rate * aratio) / frequency) * (1<<30));
+    if(ok) {
+        SET_STEPTICKER_DEBUG_PIN(1);
+        return true;
     }
-    move_issued = true;
-    stepticker_debug_pin = 0;
+
+    return false;
 }
 
+
 // returns index of the stepper motor in the array and bitset
 int StepTicker::register_motor(StepperMotor* m)
 {