stepper.c
00001 #include <stepper.h>
00002 #include <stepper-interrupt.h>
00003
00004 #ifndef NUL
00005 #define NULL 0
00006 #endif
00007
00008 static StepperAccSeq *free_seq = NULL;
00009
00010 StepperAccSeq *
00011 stepper_allocate_seq()
00012 {
00013 StepperAccSeq *seq;
00014 if (!free_seq) return NULL;
00015 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00016 seq = free_seq;
00017 free_seq = seq->next;
00018 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00019 return seq;
00020 }
00021
00022
00023 void
00024 stepper_free_seq(StepperAccSeq *seq)
00025 {
00026 StepperAccSeq *s;
00027 if (!seq) return;
00028 s = seq;
00029 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00030 while(s->next) s = s->next;
00031 s->next = free_seq;
00032 free_seq = seq;
00033 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00034 }
00035
00036 static void
00037 stepper_state_init(StepperState *stepper)
00038 {
00039 stepper->step_count = 0;
00040 stepper->io_mask = 0;
00041 stepper->acc_steps = NULL;
00042 stepper->run_steps = NULL;
00043 stepper->hold_steps = NULL;
00044 stepper->current_step = 0;
00045 stepper->sequence_length = 0;
00046
00047 stepper->velocity = 0;
00048 stepper->acceleration = 0;
00049 stepper->step_full = 0;
00050 stepper->step_frac = 0;
00051 stepper->n_steps = 0;
00052
00053 #ifdef TIMING_ERRORS
00054 stepper->err_min = TIMER_FREQ;
00055 stepper->err_max = -TIMER_FREQ;
00056 #endif
00057
00058 }
00059
00060 void
00061 stepper_init(AT91PS_TC timer, unsigned int id)
00062 {
00063 unsigned int s;
00064 stepper_context.flags = 0;
00065 stepper_context.timer_channel = timer;
00066 stepper_context.steps = NULL;
00067 stepper_context.current_step = NULL;
00068 stepper_context.period_count = 0;
00069 stepper_context.user_callback = NULL;
00070
00071 for (s = 0; s < NUM_STEPPERS; s++) {
00072 stepper_state_init(&stepper_context.steppers[s]);
00073 }
00074 timer->TC_CMR = (AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO
00075 | AT91C_TC_CLKS_TIMER_DIV3_CLOCK);
00076 timer->TC_RC = TIMER_FREQ / PPS;
00077 timer->TC_RA = 0xffff;
00078 timer->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00079 *AT91C_PMC_PCER = (1 << id);
00080
00081 AT91C_AIC_SMR[id] = AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | 7;
00082 AT91C_AIC_SVR[id] = (unsigned long)stepper_timer_interrupt;
00083 *AT91C_AIC_IECR = (1 << id);
00084 timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
00085 }
00086
00087 void
00088 stepper_init_io(unsigned int stepper_index, uint32_t mask,
00089 const uint32_t *acc, const uint32_t *run,
00090 const uint32_t *hold, unsigned int nsteps)
00091 {
00092 StepperState *state;
00093 if (stepper_index >= NUM_STEPPERS) return;
00094 state = &stepper_context.steppers[stepper_index];
00095
00096 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00097
00098 state->io_mask = mask;
00099 state->acc_steps = acc;
00100 state->run_steps = run;
00101 state->hold_steps = hold;
00102 state->current_step = 0;
00103 state->sequence_length = nsteps;
00104 *AT91C_PIOA_OWER = mask;
00105 *AT91C_PIOA_MDDR = mask;
00106
00107 *AT91C_PIOA_ODSR = ((*AT91C_PIOA_ODSR & ~mask)
00108 | (state->hold_steps[0] & mask));
00109 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00110 *AT91C_PIOA_OER = mask;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 StepperResult
00128 stepper_add_acc_seq(unsigned int stepper_index, StepperAccSeq *new_seq)
00129 {
00130 StepperResult res = STEPPER_ERR_TOO_LATE;
00131 StepperAccSeq **seqp;
00132 StepperState *state;
00133 if (stepper_index >= NUM_STEPPERS) return STEPPER_ERR_INDEX;
00134 state = &stepper_context.steppers[stepper_index];
00135 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00136 seqp = &state->acceleration_sequence;
00137 while(*seqp && ((*seqp)->period < new_seq->period || ((*seqp)->period == new_seq->period && (*seqp)->acceleration == STEPPER_ACC_INVALID))) {
00138 seqp = &(*seqp)->next;
00139 }
00140 if (new_seq->period > stepper_context.period_count + 1) {
00141
00142 if (*seqp) stepper_free_seq(*seqp);
00143 *seqp = new_seq;
00144 res = STEPPER_OK;
00145 }
00146 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00147 return res;
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 StepperResult
00165 stepper_insert_callback(unsigned int stepper_index, unsigned int period)
00166 {
00167 StepperResult res = STEPPER_ERR_TOO_LATE;
00168 StepperAccSeq **seqp;
00169 StepperState *state;
00170 if (stepper_index >= NUM_STEPPERS) return STEPPER_ERR_INDEX;
00171 state = &stepper_context.steppers[stepper_index];
00172 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00173 seqp = &state->acceleration_sequence;
00174 while(*seqp && (*seqp)->period < period) {
00175 seqp = &(*seqp)->next;
00176 }
00177 if (period > stepper_context.period_count + 1) {
00178 StepperAccSeq *new_seq = stepper_allocate_seq();
00179 if (!new_seq) {
00180 res = STEPPER_ERR_MEM;
00181 } else {
00182 new_seq->next = *seqp;
00183 *seqp = new_seq;
00184 new_seq->period = period;
00185 new_seq->acceleration = STEPPER_ACC_INVALID;
00186 res = STEPPER_OK;
00187 }
00188 }
00189 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00190 return res;
00191 }
00192
00193 StepperResult
00194 stepper_add_acc(unsigned int stepper_index, unsigned int period, long acc)
00195 {
00196 StepperAccSeq *seq = stepper_allocate_seq();
00197
00198 if (!seq) return STEPPER_ERR_MEM;
00199 seq->next = NULL;
00200 seq->period = period;
00201 seq->acceleration = acc;
00202 return stepper_add_acc_seq(stepper_index, seq);
00203 }
00204
00205 void
00206 stepper_set_callback_proc(StepperUserCallback callback)
00207 {
00208 stepper_context.user_callback = callback;
00209 }
00210
00211 unsigned long
00212 stepper_current_period()
00213 {
00214 return stepper_context.period_count;
00215 }
00216
00217 long
00218 stepper_current_step(unsigned int stepper_index)
00219 {
00220 StepperState *state = &stepper_context.steppers[stepper_index];
00221 return state->step_count;
00222 }
00223
00224 long long
00225 stepper_step_frac(unsigned int stepper_index)
00226 {
00227 long long s;
00228 StepperState *state = &stepper_context.steppers[stepper_index];
00229 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00230 s = state->step_full * DIST_SCALE + state->step_frac;
00231 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00232 return s;
00233 }
00234
00235 long
00236 stepper_current_velocity(unsigned int stepper_index)
00237 {
00238 StepperState *state = &stepper_context.steppers[stepper_index];
00239 return state->velocity;
00240 }
00241
00242
00243
00244 unsigned long
00245 stepper_velocity(unsigned int stepper_index, unsigned long period)
00246 {
00247 long a;
00248 long v;
00249 unsigned long t;
00250 StepperState *state;
00251 StepperAccSeq *seq;
00252 state = &stepper_context.steppers[stepper_index];
00253
00254 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00255 seq = state->acceleration_sequence;
00256 a = state->acceleration;
00257 v = state->velocity;
00258 t = stepper_context.period_count + 2;
00259
00260 while(seq && seq->period < period) {
00261 v += a * (seq->period - t);
00262 t = seq->period;
00263 a = seq->acceleration;
00264 seq = seq->next;
00265 }
00266 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00267 v += a * (period - t);
00268 return v;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 StepperResult
00282 stepper_state_at(unsigned int stepper_index, unsigned long period,
00283 long *velocity, long long *position)
00284 {
00285 long a;
00286 long v;
00287 long long s;
00288 unsigned long t;
00289 long dt;
00290 StepperState *state;
00291 StepperAccSeq *seq;
00292 state = &stepper_context.steppers[stepper_index];
00293
00294 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00295 if (period < stepper_context.period_count + 2) {
00296 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00297 return STEPPER_ERR_TOO_LATE;
00298 }
00299 seq = state->acceleration_sequence;
00300 a = state->acceleration;
00301 v = state->velocity;
00302 t = stepper_context.period_count + 2;
00303 s = state->step_full * (long long)DIST_SCALE + state->step_frac;
00304 while(seq && seq->period < period) {
00305 dt = seq->period - t;
00306 s += (a * (long long)dt + 2 * v) * dt;
00307 v += a * (seq->period - t);
00308 t = seq->period;
00309 a = seq->acceleration;
00310 seq = seq->next;
00311 }
00312 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00313 dt = period - t;
00314 *position = s + (a * (long long)dt + (DIST_SCALE/VEL_SCALE) * v) * dt;
00315 *velocity = v + a * dt;
00316
00317 return STEPPER_OK;
00318 }
00319
00320
00321 StepperResult
00322 stepper_set_velocity(unsigned int stepper_index, unsigned long *periodp,
00323 unsigned long max_acc, long final_speed)
00324 {
00325 long start_period = *periodp;
00326 long v = stepper_velocity(stepper_index, start_period);
00327
00328 if (final_speed == v) {
00329 return stepper_add_acc(stepper_index, start_period, 0);
00330 } else {
00331 StepperResult res;
00332 long a = (final_speed > v) ? max_acc : -max_acc;
00333 long t = ((long)(final_speed - v)) / a;
00334 long diff = (final_speed - v) - t * a;
00335 if (t > 0) {
00336 res = stepper_add_acc(stepper_index, start_period, a);
00337 if (res != STEPPER_OK) return res;
00338 }
00339 if (diff) {
00340 res = stepper_add_acc(stepper_index, start_period+t, diff);
00341 if (res != STEPPER_OK) return res;
00342 t++;
00343 }
00344 *periodp = start_period+t;
00345 return stepper_add_acc(stepper_index, start_period+t, 0);
00346 }
00347 }
00348
00349 #ifdef TIMING_ERRORS
00350 void
00351 stepper_timing_errors(unsigned int stepper_index, long *min, long *max)
00352 {
00353 StepperState *state;
00354 state = &stepper_context.steppers[stepper_index];
00355 *min = state->err_min;
00356 *max = state->err_max;
00357 state->err_max = -TIMER_FREQ;
00358 state->err_min = TIMER_FREQ;
00359 }
00360 #endif