Contiki 2.6
|
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 }