stepper-interrupt.c
00001 #include <stepper-interrupt.h>
00002 #include <interrupt-utils.h>
00003 #include <stdio.h>
00004 #include <stepper.h>
00005
00006
00007
00008 StepperContext stepper_context;
00009
00010
00011 static void
00012 do_step(StepperTimerStep *step)
00013 {
00014 const uint32_t *io_steps;
00015 StepperState *state = step->state;
00016
00017
00018 if (step->power >= STEPPER_POWER_ACC) {
00019 io_steps = state->acc_steps;
00020 } else if (step->power >= STEPPER_POWER_RUN) {
00021 io_steps = state->run_steps;
00022 } else {
00023 io_steps = state->hold_steps;
00024 }
00025 if (io_steps) {
00026 if (step->direction == STEPPER_DIRECTION_FORWARD){
00027 state->step_count++;
00028
00029 if (++state->current_step == state->sequence_length)
00030 state->current_step = 0;
00031 } else {
00032 state->step_count--;
00033
00034 if (state->current_step-- == 0)
00035 state->current_step = state->sequence_length-1;
00036 }
00037 *AT91C_PIOA_ODSR = (*AT91C_PIOA_ODSR & ~state->io_mask)
00038 | (io_steps[state->current_step] & state->io_mask);
00039 #ifdef TIMING_ERRORS
00040 {
00041 long err = ((long)stepper_context.timer_channel->TC_CV - (long)step->time);
00042 if (err >= (TIMER_FREQ/PPS/2)) {
00043 err -= TIMER_FREQ/PPS;
00044 } else if (err < -(TIMER_FREQ/PPS/2)) {
00045 err += TIMER_FREQ/PPS;
00046 }
00047 if (err < state->err_min) state->err_min = err;
00048 if (err > state->err_max) state->err_max = err;
00049 }
00050 #endif
00051 }
00052 }
00053
00054 static void
00055 set_hold(StepperState *state) {
00056 *AT91C_PIOA_ODSR = (*AT91C_PIOA_ODSR & ~state->io_mask)
00057 | (state->hold_steps[state->current_step] & state->io_mask);
00058 }
00059 static void
00060 advance_step()
00061 {
00062 StepperTimerStep *current =stepper_context.current_step;
00063 AT91PS_TC timer = stepper_context.timer_channel;
00064 unsigned int now = timer->TC_CV;
00065 while (current && current->time <= now) {
00066 do_step(current);
00067 current = current->next;
00068 if (!current) break;
00069 timer->TC_RA = current->time;
00070 now = timer->TC_CV;
00071 }
00072 stepper_context.current_step = current;
00073 }
00074
00075
00076 static inline int64_t
00077 mulsu48_16(int64_t a, uint32_t b)
00078 {
00079 return a*(int64_t)b;
00080 }
00081
00082
00083 static unsigned long
00084 solve_dist(long long s, long a, long long v, unsigned long t_low, unsigned long t_high)
00085 {
00086 long long s_low = mulsu48_16((a*(long)t_low+ v), t_low);
00087 long long s_high = mulsu48_16((a*(long)t_high + v), t_high);
00088 if (s >= s_low && s <= s_high) {
00089 while(t_low + 2 < t_high) {
00090 unsigned long t = (t_high + t_low) / 2;
00091 long long s_mid = mulsu48_16((a*(long)t + v), t);
00092 if (s < s_mid) {
00093 t_high = t;
00094 s_high = s_mid;
00095 } else {
00096 t_low = t;
00097 s_low = s_mid;
00098 }
00099 }
00100 } else {
00101 while(t_low + 1 < t_high) {
00102 unsigned long t = (t_high + t_low) / 2;
00103 long long s_mid = mulsu48_16((a*(long)t + v), t);
00104 if (s > s_mid) {
00105 t_high = t;
00106 s_high = s_mid;
00107 } else {
00108 t_low = t;
00109 s_low = s_mid;
00110 }
00111 }
00112 }
00113 return (t_high + t_low) / 2;
00114 }
00115
00116
00117 #define HEAP_SIZE 65
00118 static StepperTimerStep step_heap[2][HEAP_SIZE];
00119 static unsigned short heap_pos = 0;
00120 static unsigned char current_heap = 0;
00121
00122 static StepperTimerStep *
00123 allocate_step()
00124 {
00125 if (heap_pos >= HEAP_SIZE) return NULL;
00126 return &step_heap[current_heap][heap_pos++];
00127 }
00128
00129 static void
00130 switch_step_heap()
00131 {
00132 current_heap ^= 1;
00133 heap_pos = 0;
00134 }
00135
00136 StepperTimerStep **
00137 insert_step(StepperTimerStep **at, StepperState *state,
00138 unsigned int time, uint8_t direction, uint8_t power)
00139 {
00140 StepperTimerStep *new_step;
00141 while(*at && (*at)->time <= time) {
00142 at = &(*at)->next;
00143 }
00144 new_step = allocate_step();
00145 if (!new_step) return at;
00146 new_step->next = *at;
00147 new_step->state = state;
00148 new_step->time = time;
00149 new_step->direction = direction;
00150 new_step->power = power;
00151 *at = new_step;
00152
00153 return &new_step->next;
00154 }
00155
00156
00157 static uint8_t
00158 get_power(StepperState *state)
00159 {
00160 if (state->acceleration != 0) return STEPPER_POWER_ACC;
00161 if (state->velocity == 0) return STEPPER_POWER_HOLD;
00162 return STEPPER_POWER_RUN;
00163 }
00164
00165 #define SQ(x) ((x)*(x))
00166 #define S_SCALING ((2LL*SQ((long long)TIMER_FREQ)) / DIST_SCALE )
00167 #define V_SCALING (2LL*TIMER_FREQ/VEL_SCALE)
00168
00169
00170 static void
00171 step_interval(StepperState *state)
00172 {
00173 unsigned int i;
00174 long long v = state->velocity * V_SCALING;
00175 long long a = state->acceleration;
00176 unsigned long t = 0;
00177 StepperTimerStep **at = &stepper_context.steps;
00178 if (state->n_steps >= 0) {
00179 long long s = -state->step_frac * S_SCALING;
00180 for (i = 0; i < state->n_steps; i++) {
00181 s+= DIST_SCALE * S_SCALING;
00182 t = solve_dist(s, a, v, t, TIMER_FREQ/PPS);
00183
00184 at = insert_step(at, state, t, STEPPER_DIRECTION_FORWARD, get_power(state));
00185 }
00186 } else {
00187 long long s = (DIST_SCALE - state->step_frac) * S_SCALING;
00188 for (i = 0; i < -state->n_steps; i++) {
00189 s-= DIST_SCALE * S_SCALING;
00190 t = solve_dist(s, a, v, t, TIMER_FREQ/PPS);
00191
00192 at = insert_step(at, state, t, STEPPER_DIRECTION_BACKWARD, get_power(state));
00193 }
00194 }
00195 }
00196 static void
00197 setup_speed(StepperState *state)
00198 {
00199 long steps;
00200 long step_frac;
00201
00202
00203 step_frac = (state->acceleration + 2 * state->velocity
00204 + state->step_frac);
00205 steps = step_frac / DIST_SCALE;
00206 step_frac -= steps * DIST_SCALE;
00207 if (step_frac <0) {
00208 step_frac += DIST_SCALE;
00209 steps--;
00210 }
00211
00212
00213
00214 state->n_steps = steps;
00215 step_interval(state);
00216 state->velocity += state->acceleration;
00217 state->step_frac = step_frac;
00218 state->step_full += steps;
00219 }
00220
00221 static void
00222 advance_period()
00223 {
00224 unsigned int s;
00225 StepperTimerStep *current =stepper_context.current_step;
00226
00227 while (current) {
00228 do_step(current);
00229 current = current->next;
00230 }
00231
00232 stepper_context.current_step = stepper_context.steps;
00233 stepper_context.steps = NULL;
00234 if (stepper_context.current_step) {
00235 stepper_context.timer_channel->TC_RA = stepper_context.current_step->time;
00236 } else {
00237 stepper_context.timer_channel->TC_RA = 0xffff;
00238 }
00239
00240 advance_step();
00241 stepper_context.period_count++;
00242 *AT91C_AIC_EOICR = 0;
00243 for(s = 0; s < NUM_STEPPERS; s++) {
00244 StepperState *state = &stepper_context.steppers[s];
00245 StepperAccSeq *acc_seq;
00246 if (state->acceleration == 0 && state->velocity == 0) {
00247
00248 stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
00249 set_hold(state);
00250 stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
00251 }
00252 while ((acc_seq = state->acceleration_sequence)
00253 && acc_seq->period == stepper_context.period_count + 1) {
00254 state->acceleration_sequence = acc_seq->next;
00255 if (acc_seq->acceleration == STEPPER_ACC_INVALID) {
00256 if (stepper_context.user_callback) {
00257 stepper_context.user_callback(s, stepper_context.period_count);
00258 }
00259 } else {
00260 state->acceleration = acc_seq->acceleration;
00261 }
00262 acc_seq->next = NULL;
00263 stepper_free_seq(acc_seq);
00264 }
00265 setup_speed(&stepper_context.steppers[s]);
00266 }
00267
00268 switch_step_heap();
00269 }
00270
00271
00272 static void stepper_int_safe() __attribute((noinline));
00273 static void
00274 stepper_int_safe()
00275 {
00276 unsigned int status;
00277 status = stepper_context.timer_channel->TC_SR;
00278 if (status & AT91C_TC_CPAS) {
00279 advance_step();
00280
00281 }
00282 if (status & AT91C_TC_CPCS) {
00283 advance_period();
00284 } else {
00285 *AT91C_AIC_EOICR = 0;
00286 }
00287
00288 }
00289
00290 void NACKEDFUNC stepper_timer_interrupt (void) {
00291 ISR_STORE();
00292 ISR_ENABLE_NEST();
00293 stepper_int_safe();
00294 ISR_DISABLE_NEST();
00295 ISR_RESTORE();
00296 }