Thursday, June 28, 2007

64 bits and timers on AVR

Inclusion of 64-bit multiplication and division increases code size by 10 kilobytes on an AVR ATmega8. Reworked the formula to avoid uint64_t-s.

Timer-based stepper movement is just great. Compared to _delay_1 or _delay_ms it offers following benefits:

  • Frees CPU up for other tasks.
  • Delay lengths are can be easily specified in milli- or microseconds.

It's not hard. I prepare a list of 'actions' to execute beforehand and set the timer top as follows:
/** Set up timer 1 (16-bit), frequency = F_CPU/(timertop+1). */
#define setup_timer1(timertop) do { \
OCR1A = (timertop); /* set top */ \
/* Mode 4 - CTC with Prescaler 1 */ \
TCCR1B = (1<<WGM12)|(1<<CS10); \
TCNT1 = 0; /* reset counter */ \
TIMSK |= (1<<OCIE1A); /* enable output-compare int */ \
} while (0)

/**
* Calculate timertop for setup_timer1.
*/
static uint16_t
timertop_of( const uint16_t length,
const uint16_t time_ms)
{
const uint16_t timertop = (((uint32_t)time_ms) * (F_CPU/100) / 10) / length - 1;
return timertop;
}

/** Current action index. */
static int8_t action_index = -1;
/** Actions are executed from back to front. */
static ACTION actions[5];


The interrupt service routine chews through the list of actions:
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
if (action_index>=0) {
ACTION* act = &actions[action_index];
move_1_step(act->step_direction);
if (--(act->countdown) == 0) {
--action_index;
}
}
}

The experienced reader can fill out the details...

No comments: