Contiki 2.5
stepper-interrupt.c
1 #include <stepper-interrupt.h>
2 #include <interrupt-utils.h>
3 #include <stdio.h>
4 #include <stepper.h>
5 
6 
7 
8 StepperContext stepper_context;
9 
10 
11 static void
12 do_step(StepperTimerStep *step)
13 {
14  const uint32_t *io_steps;
15  StepperState *state = step->state;
16 
17 
18  if (step->power >= STEPPER_POWER_ACC) {
19  io_steps = state->acc_steps;
20  } else if (step->power >= STEPPER_POWER_RUN) {
21  io_steps = state->run_steps;
22  } else {
23  io_steps = state->hold_steps;
24  }
25  if (io_steps) {
26  if (step->direction == STEPPER_DIRECTION_FORWARD){
27  state->step_count++;
28  /* dbg_putchar('+'); */
29  if (++state->current_step == state->sequence_length)
30  state->current_step = 0;
31  } else {
32  state->step_count--;
33  /* dbg_putchar('-'); */
34  if (state->current_step-- == 0)
35  state->current_step = state->sequence_length-1;
36  }
37  *AT91C_PIOA_ODSR = (*AT91C_PIOA_ODSR & ~state->io_mask)
38  | (io_steps[state->current_step] & state->io_mask);
39 #ifdef TIMING_ERRORS
40  {
41  long err = ((long)stepper_context.timer_channel->TC_CV - (long)step->time);
42  if (err >= (TIMER_FREQ/PPS/2)) {
43  err -= TIMER_FREQ/PPS;
44  } else if (err < -(TIMER_FREQ/PPS/2)) {
45  err += TIMER_FREQ/PPS;
46  }
47  if (err < state->err_min) state->err_min = err;
48  if (err > state->err_max) state->err_max = err;
49  }
50 #endif
51  }
52 }
53 
54 static void
55 set_hold(StepperState *state) {
56  *AT91C_PIOA_ODSR = (*AT91C_PIOA_ODSR & ~state->io_mask)
57  | (state->hold_steps[state->current_step] & state->io_mask);
58 }
59 static void
60 advance_step()
61 {
62  StepperTimerStep *current =stepper_context.current_step;
63  AT91PS_TC timer = stepper_context.timer_channel;
64  unsigned int now = timer->TC_CV;
65  while (current && current->time <= now) {
66  do_step(current);
67  current = current->next;
68  if (!current) break;
69  timer->TC_RA = current->time;
70  now = timer->TC_CV;
71  }
72  stepper_context.current_step = current;
73 }
74 
75 
76 static inline int64_t
77 mulsu48_16(int64_t a, uint32_t b)
78 {
79  return a*(int64_t)b;
80 }
81 
82 /* Find a solution for s = a*t*t +v * t in the interval [t_low, t_high[ */
83 static unsigned long
84 solve_dist(long long s, long a, long long v, unsigned long t_low, unsigned long t_high)
85 {
86  long long s_low = mulsu48_16((a*(long)t_low+ v), t_low);
87  long long s_high = mulsu48_16((a*(long)t_high + v), t_high);
88  if (s >= s_low && s <= s_high) {
89  while(t_low + 2 < t_high) {
90  unsigned long t = (t_high + t_low) / 2;
91  long long s_mid = mulsu48_16((a*(long)t + v), t);
92  if (s < s_mid) {
93  t_high = t;
94  s_high = s_mid;
95  } else {
96  t_low = t;
97  s_low = s_mid;
98  }
99  }
100  } else {
101  while(t_low + 1 < t_high) {
102  unsigned long t = (t_high + t_low) / 2;
103  long long s_mid = mulsu48_16((a*(long)t + v), t);
104  if (s > s_mid) {
105  t_high = t;
106  s_high = s_mid;
107  } else {
108  t_low = t;
109  s_low = s_mid;
110  }
111  }
112  }
113  return (t_high + t_low) / 2;
114 }
115 
116 
117 #define HEAP_SIZE 65
118 static StepperTimerStep step_heap[2][HEAP_SIZE];
119 static unsigned short heap_pos = 0; /* Next free position in heap */
120 static unsigned char current_heap = 0;
121 
122 static StepperTimerStep *
123 allocate_step()
124 {
125  if (heap_pos >= HEAP_SIZE) return NULL;
126  return &step_heap[current_heap][heap_pos++];
127 }
128 
129 static void
130 switch_step_heap()
131 {
132  current_heap ^= 1;
133  heap_pos = 0;
134 }
135 
136 StepperTimerStep **
137 insert_step(StepperTimerStep **at, StepperState *state,
138  unsigned int time, uint8_t direction, uint8_t power)
139 {
140  StepperTimerStep *new_step;
141  while(*at && (*at)->time <= time) {
142  at = &(*at)->next;
143  }
144  new_step = allocate_step();
145  if (!new_step) return at;
146  new_step->next = *at;
147  new_step->state = state;
148  new_step->time = time;
149  new_step->direction = direction;
150  new_step->power = power;
151  *at = new_step;
152  /* dbg_putchar('!'); */
153  return &new_step->next;
154 }
155 
156 /* Determine suitable power for the current state */
157 static uint8_t
158 get_power(StepperState *state)
159 {
160  if (state->acceleration != 0) return STEPPER_POWER_ACC;
161  if (state->velocity == 0) return STEPPER_POWER_HOLD;
162  return STEPPER_POWER_RUN;
163 }
164 
165 #define SQ(x) ((x)*(x))
166 #define S_SCALING ((2LL*SQ((long long)TIMER_FREQ)) / DIST_SCALE )
167 #define V_SCALING (2LL*TIMER_FREQ/VEL_SCALE)
168 
169 
170 static void
171 step_interval(StepperState *state)
172 {
173  unsigned int i;
174  long long v = state->velocity * V_SCALING;
175  long long a = state->acceleration;
176  unsigned long t = 0;
177  StepperTimerStep **at = &stepper_context.steps;
178  if (state->n_steps >= 0) {
179  long long s = -state->step_frac * S_SCALING;
180  for (i = 0; i < state->n_steps; i++) {
181  s+= DIST_SCALE * S_SCALING;
182  t = solve_dist(s, a, v, t, TIMER_FREQ/PPS);
183  /* printf("F%ld\n", t); */
184  at = insert_step(at, state, t, STEPPER_DIRECTION_FORWARD, get_power(state));
185  }
186  } else {
187  long long s = (DIST_SCALE - state->step_frac) * S_SCALING;
188  for (i = 0; i < -state->n_steps; i++) {
189  s-= DIST_SCALE * S_SCALING;
190  t = solve_dist(s, a, v, t, TIMER_FREQ/PPS);
191  /* printf("B%ld\n", t); */
192  at = insert_step(at, state, t, STEPPER_DIRECTION_BACKWARD, get_power(state));
193  }
194  }
195 }
196 static void
197 setup_speed(StepperState *state)
198 {
199  long steps;
200  long step_frac;
201  /* printf("%ld v= %ld s=%ld\n",stepper_context.period_count, */
202 /* state->velocity, state->step_frac); */
203  step_frac = (state->acceleration + 2 * state->velocity
204  + state->step_frac);
205  steps = step_frac / DIST_SCALE;
206  step_frac -= steps * DIST_SCALE;
207  if (step_frac <0) {
208  step_frac += DIST_SCALE;
209  steps--;
210  }
211 
212  /* printf("step_frac=%ld (%f) steps=%ld\n",step_frac, */
213 /* (double)step_frac/(double)(DIST_SCALE), steps); */
214  state->n_steps = steps;
215  step_interval(state);
216  state->velocity += state->acceleration;
217  state->step_frac = step_frac;
218  state->step_full += steps;
219 }
220 
221 static void
222 advance_period()
223 {
224  unsigned int s;
225  StepperTimerStep *current =stepper_context.current_step;
226  /* Do any remaining step */
227  while (current) {
228  do_step(current);
229  current = current->next;
230  }
231  /* Start from the beginning */
232  stepper_context.current_step = stepper_context.steps;
233  stepper_context.steps = NULL;
234  if (stepper_context.current_step) {
235  stepper_context.timer_channel->TC_RA = stepper_context.current_step->time;
236  } else {
237  stepper_context.timer_channel->TC_RA = 0xffff;
238  }
239  /* In case there is a step very early in the period */
240  advance_step();
241  stepper_context.period_count++;
242  *AT91C_AIC_EOICR = 0;
243  for(s = 0; s < NUM_STEPPERS; s++) {
244  StepperState *state = &stepper_context.steppers[s];
245  StepperAccSeq *acc_seq;
246  if (state->acceleration == 0 && state->velocity == 0) {
247  /* Set hold power if stationary */
248  stepper_context.timer_channel->TC_IDR = AT91C_TC_CPCS | AT91C_TC_CPAS;
249  set_hold(state);
250  stepper_context.timer_channel->TC_IER = AT91C_TC_CPCS | AT91C_TC_CPAS;
251  }
252  while ((acc_seq = state->acceleration_sequence)
253  && acc_seq->period == stepper_context.period_count + 1) {
254  state->acceleration_sequence = acc_seq->next;
255  if (acc_seq->acceleration == STEPPER_ACC_INVALID) {
256  if (stepper_context.user_callback) {
257  stepper_context.user_callback(s, stepper_context.period_count);
258  }
259  } else {
260  state->acceleration = acc_seq->acceleration;
261  }
262  acc_seq->next = NULL; /* Only free this one */
263  stepper_free_seq(acc_seq);
264  }
265  setup_speed(&stepper_context.steppers[s]);
266  }
267  /* Prepare heap for next period */
268  switch_step_heap();
269 }
270 
271 /* Here we have a proper stack frame and can use local variables */
272 static void stepper_int_safe() __attribute((noinline));
273 static void
274 stepper_int_safe()
275 {
276  unsigned int status;
277  status = stepper_context.timer_channel->TC_SR;
278  if (status & AT91C_TC_CPAS) {
279  advance_step();
280  /* dbg_putchar('*'); */
281  }
282  if (status & AT91C_TC_CPCS) {
283  advance_period();
284  } else {
285  *AT91C_AIC_EOICR = 0; /* End of Interrupt */
286  }
287 
288 }
289 
290 void NACKEDFUNC stepper_timer_interrupt (void) {
291  ISR_STORE();
292  ISR_ENABLE_NEST();
293  stepper_int_safe();
294  ISR_DISABLE_NEST();
295  ISR_RESTORE();
296 }