Showing posts with label avr. Show all posts
Showing posts with label avr. Show all posts

Thursday, July 5, 2007

Microstepping


Microstepping lets steppers work much faster and more reliably, not to mention smoother ride :P

The TCA3727 (looks like it will be obsolete shortly) has the following nice diagram explaining microstepping currents.

Stepping table is as follows:
#define I10 _BV(STEPPER_I10_PIN)
#define I11 _BV(STEPPER_I11_PIN)
#define PH1 _BV(STEPPER_PH1_PIN)
#define I20 _BV(STEPPER_I20_PIN)
#define I21 _BV(STEPPER_I21_PIN)
#define PH2 _BV(STEPPER_PH2_PIN)

static const u08
stepper_steps[] PROGMEM = {
I10 | I11 | 0 | PH2 | 0 | 0, // 0
0 | I11 | PH1 | PH2 | 0 | 0, // 1
I10 | 0 | PH1 | PH2 | 0 | 0, // 2
0 | 0 | PH1 | PH2 | 0 | 0, // 3
0 | 0 | PH1 | PH2 | I20 | 0, // 4
0 | 0 | PH1 | PH2 | 0 | I21, // 5
0 | 0 | PH1 | PH2 | I20 | I21, // 6
0 | 0 | PH1 | 0 | 0 | I21, // 7
0 | 0 | PH1 | 0 | I20 | 0, // 8
0 | 0 | PH1 | 0 | 0 | 0, // 9
I10 | 0 | PH1 | 0 | 0 | 0, // 10
0 | I11 | PH1 | 0 | 0 | 0, // 11
I10 | I11 | PH1 | 0 | 0 | 0, // 12
0 | I11 | 0 | 0 | 0 | 0, // 13
I10 | 0 | 0 | 0 | 0 | 0, // 14
0 | 0 | 0 | 0 | 0 | 0, // 15
0 | 0 | 0 | 0 | I20 | 0, // 16
0 | 0 | 0 | 0 | 0 | I21, // 17
0 | 0 | 0 | 0 | I20 | I21, // 18
0 | 0 | 0 | PH2 | 0 | I21, // 19
0 | 0 | 0 | PH2 | I20 | 0, // 20
0 | 0 | 0 | PH2 | 0 | 0, // 21
I10 | 0 | 0 | PH2 | 0 | 0, // 22
0 | I11 | 0 | PH2 | 0 | 0 // 23
};

#undef I10
#undef I11
#undef PH1
#undef I20
#undef I21
#undef PH2

When doing it step-by-step, some steps seem to be less "powerful" than others. It doesn't run _very_ smoothly on higher speeds. Perhaps some tweaking with step timings is neede in order to achieve really smooth operation.

Wednesday, July 4, 2007

Harvard Architecture Lesson

AVR has Harvard architecture. The program and data memory are totally separate entities. However, pointers to program memory have the same type as pointers to data memory.

This solved my yesterdays mysterious printouts. I was passing "const char*" to a function that was expecting "const prog_char *".

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...