Defer enabling of timer1_compa interrupt the end of the interrupt handler.

Specifically, disable interrupts just before returning and then enable
the timer interrupt if appropriate. This means that the timer interrupt
cannot actually fire until after the RETI, so the function cannot be
entered recursively.
This commit is contained in:
Jim McGee 2011-05-10 22:36:08 -07:00 committed by Michael Moon
parent 57b30b0ff1
commit 5dc0c80f0b
4 changed files with 48 additions and 19 deletions

2
dda.c
View File

@ -368,6 +368,8 @@ void dda_create(DDA *dda, TARGET *target) {
We set direction and enable outputs, and set the timer for the first step from the precalculated value. We set direction and enable outputs, and set the timer for the first step from the precalculated value.
We also mark this DDA as running, so other parts of the firmware know that something is happening We also mark this DDA as running, so other parts of the firmware know that something is happening
Called both inside and outside of interrupts.
*/ */
void dda_start(DDA *dda) { void dda_start(DDA *dda) {
// called from interrupt context: keep it simple! // called from interrupt context: keep it simple!

View File

@ -130,9 +130,20 @@ void enqueue(TARGET *t) {
MEMORY_BARRIER(); MEMORY_BARRIER();
SREG = save_reg; SREG = save_reg;
if (isdead) if (isdead) {
timer1_compa_deferred_enable = 0;
next_move(); next_move();
} if (timer1_compa_deferred_enable) {
uint8_t save_reg = SREG;
cli();
CLI_SEI_BUG_MEMORY_BARRIER();
TIMSK1 |= MASK(OCIE1A);
MEMORY_BARRIER();
SREG = save_reg;
}
}
} }
/// go to the next move. /// go to the next move.
@ -163,10 +174,10 @@ void next_move() {
else { else {
dda_start(current_movebuffer); dda_start(current_movebuffer);
} }
} }
if (queue_empty()) if (queue_empty())
setTimer(0); setTimer(0);
} }
/// DEBUG - print queue. /// DEBUG - print queue.

46
timer.c
View File

@ -41,6 +41,8 @@ volatile uint8_t clock_flag_10ms = 0;
volatile uint8_t clock_flag_250ms = 0; volatile uint8_t clock_flag_250ms = 0;
volatile uint8_t clock_flag_1s = 0; volatile uint8_t clock_flag_1s = 0;
volatile uint8_t timer1_compa_deferred_enable = 0;
/// comparator B is the system clock, happens every TICK_TIME /// comparator B is the system clock, happens every TICK_TIME
ISR(TIMER1_COMPB_vect) { ISR(TIMER1_COMPB_vect) {
// set output compare register to the next clock tick // set output compare register to the next clock tick
@ -69,27 +71,36 @@ ISR(TIMER1_COMPB_vect) {
} }
#ifdef HOST #ifdef HOST
void timer1_compa_isr(void) __attribute__ ((hot));
void timer1_compa_isr() {
// led on
WRITE(SCK, 1);
// disable this interrupt. if we set a new timeout, it will be re-enabled when appropriate
TIMSK1 &= ~MASK(OCIE1A);
// stepper tick
queue_step();
// led off
WRITE(SCK, 0);
}
/// comparator A is the step timer. It has higher priority then B. /// comparator A is the step timer. It has higher priority then B.
ISR(TIMER1_COMPA_vect) { ISR(TIMER1_COMPA_vect) {
// Check if this is a real step, or just a next_step_time "overflow" // Check if this is a real step, or just a next_step_time "overflow"
if (next_step_time < 65536) { if (next_step_time < 65536) {
// step! // step!
timer1_compa_isr(); WRITE(SCK, 1);
// disable this interrupt. if we set a new timeout, it will be re-enabled when appropriate
TIMSK1 &= ~MASK(OCIE1A);
timer1_compa_deferred_enable = 0;
// stepper tick
queue_step();
// led off
WRITE(SCK, 0);
// Enable the timer1_compa interrupt, if needed,
// but only do it after disabling global interrupts.
// This will cause push any possible timer1a interrupt
// to the far side of the return, protecting the
// stack from recursively clobbering memory.
cli();
CLI_SEI_BUG_MEMORY_BARRIER();
if (timer1_compa_deferred_enable) {
TIMSK1 |= MASK(OCIE1A);
}
return; return;
} }
@ -169,11 +180,14 @@ void setTimer(uint32_t delay)
OCR1A = step_start; OCR1A = step_start;
} }
TIMSK1 |= MASK(OCIE1A); // Defer the enabling of the timer1_CompA interrupts.
timer1_compa_deferred_enable = 1;
} else { } else {
// flag: move has ended // flag: move has ended
next_step_time = 0; next_step_time = 0;
TIMSK1 &= ~MASK(OCIE1A); TIMSK1 &= ~MASK(OCIE1A);
timer1_compa_deferred_enable = 0;
} }
// restore interrupt flag // restore interrupt flag

View File

@ -15,6 +15,8 @@ extern volatile uint8_t clock_flag_10ms;
extern volatile uint8_t clock_flag_250ms; extern volatile uint8_t clock_flag_250ms;
extern volatile uint8_t clock_flag_1s; extern volatile uint8_t clock_flag_1s;
extern volatile uint8_t timer1_compa_deferred_enable;
// If the specific bit is set, execute the following block exactly once // If the specific bit is set, execute the following block exactly once
// and then clear the flag. // and then clear the flag.
#define ifclock(F) for (;F;F=0 ) #define ifclock(F) for (;F;F=0 )