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       /* dbg_putchar('+'); */
00029       if (++state->current_step == state->sequence_length)
00030         state->current_step = 0;
00031     } else {
00032       state->step_count--;
00033       /* dbg_putchar('-'); */
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 /* Find a solution for s = a*t*t +v * t in the interval [t_low, t_high[ */
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; /* Next free position in heap */
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   /* dbg_putchar('!'); */
00153   return &new_step->next;
00154 }
00155 
00156 /* Determine suitable power for the current state */
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       /* printf("F%ld\n", t); */
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       /* printf("B%ld\n", t); */
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   /* printf("%ld v= %ld s=%ld\n",stepper_context.period_count, */
00202 /*       state->velocity, state->step_frac); */
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   /* printf("step_frac=%ld (%f) steps=%ld\n",step_frac, */
00213 /*       (double)step_frac/(double)(DIST_SCALE), steps); */
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   /* Do any remaining step */
00227   while (current) {
00228     do_step(current);
00229     current = current->next;
00230   }
00231   /* Start from the beginning */
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   /* In case there is a step very early in the period */
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       /* Set hold power if stationary */
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; /* Only free this one */
00263       stepper_free_seq(acc_seq);
00264     }
00265     setup_speed(&stepper_context.steppers[s]);
00266   }
00267   /* Prepare heap for next period */
00268   switch_step_heap();
00269 }
00270 
00271 /* Here we have a proper stack frame and can use local variables */
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     /* dbg_putchar('*'); */
00281   }
00282   if (status & AT91C_TC_CPCS) {
00283     advance_period();
00284   } else {
00285     *AT91C_AIC_EOICR = 0;                   /* End of Interrupt */
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 }

Generated on Mon Apr 11 14:23:45 2011 for Contiki 2.5 by  doxygen 1.6.1