Set a minimum delay instead of attempting to call the timer interrupt

service routine in the case that the requested timer interval is too
small.

Calling the interrupt service routine at this point is likely to
recursively clobber the stack.

Setting a lower bounds on the interrupt delay will limit the upper
speed of pulse generation, but it should not change the relative
pulse rates, and will not recurvisely clobber the stack.

Note that the lower limit of 17 has not been researched, it is
simply the value below which the old code attempted to call
the interrupt service routine directly.
This commit is contained in:
Jim McGee 2011-05-08 23:04:54 -07:00 committed by Michael Moon
parent 8241549276
commit 57b30b0ff1
1 changed files with 31 additions and 31 deletions

62
timer.c
View File

@ -124,6 +124,12 @@ void timer_init()
/// specify how long until the step timer should fire /// specify how long until the step timer should fire
void setTimer(uint32_t delay) void setTimer(uint32_t delay)
{ {
// if the delay is too small use a minimum delay so that there is time
// to set everything up before the timer expires.
if (delay < 17 )
delay = 17;
// save interrupt flag // save interrupt flag
uint8_t sreg = SREG; uint8_t sreg = SREG;
uint16_t step_start = 0; uint16_t step_start = 0;
@ -136,40 +142,34 @@ void setTimer(uint32_t delay)
TIMSK1 |= MASK(OCIE1B); TIMSK1 |= MASK(OCIE1B);
if (delay > 0) { if (delay > 0) {
if (delay <= 16) {
// unfortunately, force registers don't trigger an interrupt, so we do the following // Assume all steps belong to one move. Within one move the delay is
// "fire" ISR- maybe it sets a new timeout // from one step to the next one, which should be more or less the same
timer1_compa_isr(); // as from one step interrupt to the next one. The last step interrupt happend
// at OCR1A, so start delay from there.
step_start = OCR1A;
if (next_step_time == 0) {
// new move, take current time as start value
step_start = TCNT1;
}
next_step_time = delay;
if (next_step_time < 65536) {
// set the comparator directly to the next real step
OCR1A = (next_step_time + step_start) & 0xFFFF;
}
else if (next_step_time < 75536) {
// Next comparator interrupt would have to trigger another
// interrupt within a short time (possibly within 1 cycle).
// Avoid the impossible by firing the interrupt earlier.
OCR1A = (step_start - 10000) & 0xFFFF;
next_step_time += 10000;
} }
else { else {
// Assume all steps belong to one move. Within one move the delay is OCR1A = step_start;
// from one step to the next one, which should be more or less the same
// as from one step interrupt to the next one. The last step interrupt happend
// at OCR1A, so start delay from there.
step_start = OCR1A;
if (next_step_time == 0) {
// new move, take current time as start value
step_start = TCNT1;
}
next_step_time = delay;
if (next_step_time < 65536) {
// set the comparator directly to the next real step
OCR1A = (next_step_time + step_start) & 0xFFFF;
}
else if (next_step_time < 75536) {
// Next comparator interrupt would have to trigger another
// interrupt within a short time (possibly within 1 cycle).
// Avoid the impossible by firing the interrupt earlier.
OCR1A = (step_start - 10000) & 0xFFFF;
next_step_time += 10000;
}
else {
OCR1A = step_start;
}
TIMSK1 |= MASK(OCIE1A);
} }
TIMSK1 |= MASK(OCIE1A);
} else { } else {
// flag: move has ended // flag: move has ended
next_step_time = 0; next_step_time = 0;