this->num_motors = 0;
this->move_issued = false;
- this->next_block = nullptr;
}
StepTicker::~StepTicker()
{
static uint32_t current_tick = 0;
- if(!move_issued) return; // if nothing has been setup we ignore the ticks
+ 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);
+ }
current_tick++; // count number of ticks
bool still_moving = false;
- // currently taking 13us when no step, and 20 when 1 step
- // 21us when two motors and 36 when step
- stepticker_debug_pin = 1;
// 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
}
}
}
- stepticker_debug_pin = 0;
// 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,
// get next static block and tick info from next block
// do it here so there is no delay in ticks
- if(next_block != nullptr) {
+ if(!jobq.empty()) {
#ifdef STEPTICKER_DEBUG_PIN
stepticker_debug_pin = 1;
#endif
- // copy data
- copy_block(next_block);
- next_block = nullptr;
+ // 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
}
// called in ISR if running, else can be called from anything to start
void StepTicker::copy_block(Block *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;
tick_info[m].plateau_rate= floorf(((block->maximum_rate * aratio) / frequency) * (1<<30));
}
move_issued = true;
+ stepticker_debug_pin = 0;
}
// returns index of the stepper motor in the array and bitset
void set_unstep_time( float microseconds );
int register_motor(StepperMotor* motor);
float get_frequency() const { return frequency; }
-
+ bool is_moving(int i) const { return tick_info[i].steps_to_move != 0; }
+ uint32_t get_stepped(int i) const { return tick_info[i].step_count; }
void unstep_tick();
void step_tick (void);
void handle_finish (void);
void start();
- void copy_block(Block *block);
- void set_next_block(Block *block) { next_block= block; }
- bool is_next_block() const { return next_block != nullptr; }
+ bool add_job(Block *block) { return jobq.put(block); }
+ bool is_jobq_full() const { return jobq.full(); }
// whatever setup the block should register this to know when it is done
std::function<void()> finished_fnc{nullptr};
private:
static StepTicker *instance;
+ //
+ // Simple fixed size ring buffer.
+ // Manage objects by value.
+ // Thread safe for single Producer and single Consumer.
+ // By Dennis Lang http://home.comcast.net/~lang.dennis/code/ring/ring.html
+ // Slightly modified for naming
+
+ template <class T, size_t RingSize>
+ class TSRingBuffer
+ {
+ public:
+ TSRingBuffer()
+ : m_size(RingSize), m_buffer(new T[RingSize]), m_rIndex(0), m_wIndex(0)
+ { }
+
+ ~TSRingBuffer()
+ {
+ delete [] m_buffer;
+ };
+
+ size_t next(size_t n) const
+ {
+ return (n + 1) % m_size;
+ }
+
+ bool empty() const
+ {
+ return (m_rIndex == m_wIndex);
+ }
+
+ bool full() const
+ {
+ return (next(m_wIndex) == m_rIndex);
+ }
+
+ bool put(const T &value)
+ {
+ if (full())
+ return false;
+ m_buffer[m_wIndex] = value;
+ m_wIndex = next(m_wIndex);
+ return true;
+ }
+
+ bool get(T &value)
+ {
+ if (empty())
+ return false;
+ value = m_buffer[m_rIndex];
+ m_rIndex = next(m_rIndex);
+ return true;
+ }
+
+ private:
+ size_t m_size;
+ T *m_buffer;
+
+ // volatile is only used to keep compiler from placing values in registers.
+ // volatile does NOT make the index thread safe.
+ volatile size_t m_rIndex;
+ volatile size_t m_wIndex;
+ };
+
+ void copy_block(Block *block);
+
float frequency;
uint32_t period;
std::array<StepperMotor*, k_max_actuators> motor;
uint32_t total_move_ticks;
};
block_info_t block_info;
- Block *next_block{nullptr};
+
+ TSRingBuffer<Block*, 4> jobq;
// this is the data needed to determine when each motor needs to be issued a step
struct tickinfo_t {
{
// register this motor with the step ticker, and get its index in that array and bit position
this->index= THEKERNEL->step_ticker->register_motor(this);
- this->moving = false;
- this->stepped = 0;
- this->is_move_finished = false;
- this->force_finish= false;
steps_per_mm = 1.0F;
max_rate = 50.0F;
current_position_steps= 0;
}
-// // Instruct the StepperMotor to move a certain number of steps
-// StepperMotor* StepperMotor::move( bool direction, unsigned int steps, float initial_speed)
-// {
-// set_direction(direction);
-// this->direction = direction;
-// this->force_finish= false;
-
-// // Zero our tool counters
-// this->stepped = 0;
-// return this;
-// }
-
void StepperMotor::change_steps_per_mm(float new_steps)
{
steps_per_mm = new_steps;
You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef STEPPERMOTOR_H
-#define STEPPERMOTOR_H
+#pragma once
#include "Pin.h"
#include <atomic>
inline void enable(bool state) { en_pin.set(!state); };
- bool is_moving() const { return moving; }
bool which_direction() const { return direction; }
-// void move_finished();
-// StepperMotor* move( bool direction, unsigned int steps, float initial_speed= -1.0F);
-// StepperMotor* set_speed( float speed );
float get_steps_per_second() const { return steps_per_second; }
float get_steps_per_mm() const { return steps_per_mm; }
void set_max_rate(float mr) { max_rate= mr; }
int steps_to_target(float);
- uint32_t get_stepped() const { return stepped; }
- void force_finish_move() { force_finish= true; }
friend class StepTicker;
friend class Stepper;
int32_t last_milestone_steps;
float last_milestone_mm;
- uint32_t stepped; // TBD may not be needed
volatile struct {
- volatile bool is_move_finished:1; // Whether the move just finished
- volatile bool moving:1;
- volatile bool force_finish:1; // set to force a move to finish early
bool direction:1;
};
};
-#endif
-
this->current_block = block;
// setup stepticker to execute this block
- // if it is running then add this to next block otherwise it needs to be started
- // if(!THEKERNEL->step_ticker->is_next_block()) {
-
- // }
- THEKERNEL->step_ticker->copy_block(block);
+ THEKERNEL->step_ticker->add_job(block);
}
// Current block is discarded
#include "ConfigValue.h"
#include "Config.h"
#include "checksumm.h"
-
+#include "StepTicker.h"
#define motor_driver_control_checksum CHECKSUM("motor_driver_control")
#define sense_resistor_checksum CHECKSUM("sense_resistor")
} else {
// TODO hardcoded for X need to select ABC as needed
- bool moving = THEKERNEL->robot->actuators[0]->is_moving();
+ bool moving = THEKERNEL->step_ticker->is_moving(0);
// dump out in the format that the processing script needs
if (moving) {
- stream->printf("#sg%d,p%lu,k%u,r,", getCurrentStallGuardReading(), THEKERNEL->robot->actuators[0]->get_stepped(), getCoolstepCurrent());
+ stream->printf("#sg%d,p%lu,k%u,r,", getCurrentStallGuardReading(), THEKERNEL->step_ticker->get_stepped(0), getCoolstepCurrent());
} else {
readStatus(TMC26X_READOUT_POSITION); // get the status bits
stream->printf("#s,");