time to save again, looking good so far

This commit is contained in:
Michael Moon 2010-01-16 20:20:15 +11:00
parent 1e6c74096e
commit 90ea2910aa
10 changed files with 416 additions and 162 deletions

View File

@ -14,7 +14,7 @@
PROGRAM = mendel
SOURCES = $(PROGRAM).c ringbuffer.c serial.c dda.c gcode.c pinout.c
SOURCES = $(PROGRAM).c ringbuffer.c serial.c dda.c gcode.c timer.c
##############################################################################
# #
@ -46,10 +46,10 @@ PROGBAUD = 19200
OBJ = $(patsubst %.c,%.o,${SOURCES})
.PHONY: all program clean
.PHONY: all program clean size
.PRECIOUS: %.o %.elf
all: $(PROGRAM).hex $(PROGRAM).lst
all: $(PROGRAM).hex $(PROGRAM).lst size
program: $(PROGRAM).hex
stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
@ -60,6 +60,9 @@ program: $(PROGRAM).hex
clean:
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~
size: $(PROGRAM).hex
@objdump -h mendel.elf | perl -ne '/.(data|text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf "%d bytes (%d%% of %dkb)\n", $$a, $$a * 100 / 16384, 16 }'
%.o: %.c
$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $^

View File

@ -2,6 +2,8 @@
#include <string.h>
#include "timer.h"
extern struct {
volatile int32_t X;
volatile int32_t Y;
@ -10,10 +12,53 @@ extern struct {
volatile int32_t F;
} current_position;
// courtesy of http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml
uint8_t mb_head = 0;
uint8_t mb_tail = 0;
DDA movebuffer[MOVEBUFFER_SIZE];
uint8_t queue_full() {
if (mb_tail == 0)
return mb_head == (MOVEBUFFER_SIZE - 1);
else
return mb_head == (mb_tail - 1);
}
inline uint8_t queue_empty() {
return (mb_tail == mb_head) && !movebuffer[tail].live;
}
void enqueue(TARGET *t) {
while (queue_full())
delay(WAITING_DELAY);
uint8_t h = mb_head;
h++;
if (h == MOVEBUFFER_SIZE)
h = 0;
mb_head = h;
dda_create(t, &movebuffer[h]);
}
void next_move() {
if ((mb_tail == mb_head) && (!movebuffer[mb_tail].live)) {
// queue is empty
disable_steppers();
setTimer(DEFAULT_TICK);
}
else {
uint8_t t = mb_tail;
t++;
if (t == MOVEBUFFER_SIZE)
t = 0;
mb_tail = t;
dda_start(&movebuffer[t]);
}
}
// courtesy of http://www.oroboro.com/rafael/docserv.php/index/programming/article/distance
uint32_t approx_distance( int32_t dx, int32_t dy )
{
uint32_t min, max;
uint32_t min, max, approx;
if ( dx < 0 ) dx = -dx;
if ( dy < 0 ) dy = -dy;
@ -27,32 +72,80 @@ uint32_t approx_distance( int32_t dx, int32_t dy )
max = dx;
}
// coefficients equivalent to ( 123/128 * max ) and ( 51/128 * min )
return ((( max << 8 ) + ( max << 3 ) - ( max << 4 ) - ( max << 1 ) +
( min << 7 ) - ( min << 5 ) + ( min << 3 ) - ( min << 1 )) >> 8 );
approx = ( max * 1007 ) + ( min * 441 );
if ( max < ( min << 4 ))
approx -= ( max * 40 );
// add 512 for proper rounding
return (( approx + 512 ) >> 10 );
}
// courtesy of http://www.oroboro.com/rafael/docserv.php/index/programming/article/distance
uint32_t approx_distance_3( int32_t dx, int32_t dy, int32_t dz )
{
uint32_t min, med, max, approx;
if ( dx < 0 ) dx = -dx;
if ( dy < 0 ) dy = -dy;
if ( dz < 0 ) dz = -dz;
if ( dx < dy )
{
min = dy;
med = dx;
} else {
min = dx;
med = dy;
}
if ( dz < (int32_t)min )
{
max = med;
med = min;
min = dz;
} else if ( dz < (int32_t)med ) {
max = med;
med = dz;
} else {
max = dz;
}
approx = ( max * 860 ) + ( med * 851 ) + ( min * 520 );
if ( max < ( med << 1 )) approx -= ( max * 294 );
if ( max < ( min << 2 )) approx -= ( max * 113 );
if ( med < ( min << 2 )) approx -= ( med * 40 );
// add 512 for proper rounding
return (( approx + 512 ) >> 10 );
}
/*
CREATE
*/
void dda_create(GCODE_COMMAND *cmd, DDA *dda) {
void dda_create(TARGET *target, DDA *dda) {
static TARGET startpoint = { 0, 0, 0, 0, 0 };
// we start at the previous endpoint
memcpy(&dda->currentpoint, &startpoint, sizeof(TARGET));
// we end at the passed command's endpoint
memcpy(&dda->endpoint, &cmd->target, sizeof(TARGET));
memcpy(&dda->endpoint, target, sizeof(TARGET));
dda->x_delta = dda->endpoint.X - startpoint.X;
dda->y_delta = dda->endpoint.Y - startpoint.Y;
dda->z_delta = dda->endpoint.Z - startpoint.Z;
// always relative
dda->e_delta = dda->endpoint.E;
// always absolute
dda->f_delta = dda->endpoint.F - startpoint.F;
dda->distance = approx_distance(dda->x_delta, dda->y_delta);
// since it's unusual to combine X, Y and Z changes in a single move on reprap, check if we can use simpler approximations before trying the full 3d approximation.
if (dda->z_delta == 0)
dda->distance = approx_distance(dda->x_delta, dda->y_delta);
else if (dda->x_delta == 0 && dda->y_delta == 0)
dda->distance = dda->z_delta;
else
dda->distance = approx_distance_3(dda->x_delta, dda->y_delta, dda->z_delta);
if (dda->distance < 2)
dda->distance = dda->e_delta;
@ -62,6 +155,9 @@ void dda_create(GCODE_COMMAND *cmd, DDA *dda) {
dda->total_steps = dda->x_delta;
if (dda->y_delta > dda->total_steps)
dda->total_steps = dda->y_delta;
if (dda->z_delta > dda->total_steps)
dda->total_steps = dda->z_delta;
if (dda->e_delta > dda->total_steps)
dda->total_steps = dda->e_delta;
if (dda->f_delta > dda->total_steps)
@ -79,7 +175,6 @@ void dda_create(GCODE_COMMAND *cmd, DDA *dda) {
// dda->endpoint.F = distance / total_steps;
if (dda->f_delta > dda->total_steps) {
// TODO: rescale F
dda->f_scale = dda->f_delta / dda->total_steps;
if (dda->f_scale > 3) {
dda->f_delta /= dda->f_scale;
@ -92,14 +187,22 @@ void dda_create(GCODE_COMMAND *cmd, DDA *dda) {
dda->x_direction = (dda->endpoint.X > startpoint.X)?1:0;
dda->y_direction = (dda->endpoint.Y > startpoint.Y)?1:0;
dda->z_direction = (dda->endpoint.Z > startpoint.Z)?1:0;
dda->e_direction = (dda->endpoint.E > startpoint.E)?1:0;
dda->f_direction = (dda->endpoint.F > startpoint.F)?1:0;
dda->x_counter = dda->y_counter = dda->e_counter = dda->f_counter
dda->x_counter = dda->y_counter = dda->z_counter = dda->e_counter = dda->f_counter
= -(dda->total_steps >> 1);
// pre-calculate move speed in millimeter microseconds per step minute for less math in interrupt context
// mm (distance) * 60000000 us/min / step (total_steps) = mm.us per step.min
// mm.us per step.min / mm/min (F) = us per step
dda->move_duration = dda->distance * 60000000 / dda->total_steps;
// next dda starts where we finish
memcpy(&startpoint, &dda->endpoint, sizeof(TARGET));
dda->live = 0;
}
/*
@ -107,10 +210,17 @@ void dda_create(GCODE_COMMAND *cmd, DDA *dda) {
*/
void dda_start(DDA *dda) {
// called from interrupt context: keep it simple!
if (dda->nullmove)
return;
x_direction(dda->x_direction);
y_direction(dda->y_direction);
z_direction(dda->z_direction);
e_direction(dda->e_direction);
enable_steppers();
dda->live = 1;
}
/*
@ -147,16 +257,17 @@ void dda_step(DDA *dda) {
step_option |= can_step(x_min(), x_max(), current_position.X, dda->endpoint.X, dda->x_direction) & X_CAN_STEP;
step_option |= can_step(y_min(), y_max(), current_position.Y, dda->endpoint.Y, dda->y_direction) & Y_CAN_STEP;
step_option |= can_step(z_min(), z_max(), current_position.Z, dda->endpoint.Z, dda->z_direction) & Z_CAN_STEP;
step_option |= can_step(-1, -1, current_position.E, dda->endpoint.E, dda->e_direction) & E_CAN_STEP;
step_option |= can_step(-1, -1, current_position.F, dda->endpoint.F, dda->f_direction) & F_CAN_STEP;
step_option |= can_step(-1 , -1 , current_position.E, dda->endpoint.E, dda->e_direction) & E_CAN_STEP;
step_option |= can_step(-1 , -1 , current_position.F, dda->endpoint.F, dda->f_direction) & F_CAN_STEP;
if (step_option & X_CAN_STEP) {
dda->x_counter += dda->x_delta;
if (dda->x_counter > 0) {
dda->x_counter -= dda->x_delta;
if (dda->x_counter < 0) {
step_option |= REAL_MOVE;
// do X step
dda->x_counter -= dda->total_steps;
x_step();
dda->x_counter += dda->total_steps;
if (dda->x_direction)
current_position.X++;
@ -166,12 +277,13 @@ void dda_step(DDA *dda) {
}
if (step_option & Y_CAN_STEP) {
dda->y_counter += dda->y_delta;
if (dda->y_counter > 0) {
dda->y_counter -= dda->y_delta;
if (dda->y_counter < 0) {
step_option |= REAL_MOVE;
// do Y step
dda->y_counter -= dda->total_steps;
y_step();
dda->y_counter += dda->total_steps;
if (dda->y_direction)
current_position.Y++;
@ -181,12 +293,13 @@ void dda_step(DDA *dda) {
}
if (step_option & Z_CAN_STEP) {
dda->z_counter += dda->z_delta;
if (dda->z_counter > 0) {
dda->z_counter -= dda->z_delta;
if (dda->z_counter < 0) {
step_option |= REAL_MOVE;
// do Z step
dda->z_counter -= dda->total_steps;
z_step();
dda->z_counter += dda->total_steps;
if (dda->z_direction)
current_position.Z++;
@ -196,12 +309,13 @@ void dda_step(DDA *dda) {
}
if (step_option & E_CAN_STEP) {
dda->e_counter += dda->e_delta;
if (dda->e_counter > 0) {
dda->e_counter -= dda->e_delta;
if (dda->e_counter < 0) {
step_option |= REAL_MOVE;
// do E step
dda->e_counter -= dda->total_steps;
e_step();
dda->e_counter += dda->total_steps;
if (dda->e_direction)
current_position.E++;
@ -211,10 +325,10 @@ void dda_step(DDA *dda) {
}
if (step_option & F_CAN_STEP) {
dda->f_counter += dda->f_delta;
if (dda->f_counter > 0) {
// do F step
dda->f_counter -= dda->total_steps;
dda->f_counter -= dda->f_delta;
if (dda->f_counter < 0) {
dda->f_counter += dda->total_steps;
if (dda->f_direction)
current_position.F += dda->f_scale;
@ -222,9 +336,14 @@ void dda_step(DDA *dda) {
current_position.F -= dda->f_scale;
}
}
} while (((step_option & REAL_MOVE) == 0) && (step_option & F_CAN_STEP));
} while ( ((step_option & REAL_MOVE ) == 0) &&
((step_option & F_CAN_STEP) != 0) );
unstep();
if (step_option & REAL_MOVE) {
setTimer(dda->distance * (60000000 / current_position.F / dda->total_steps));
setTimer(dda->move_duration / current_position.F);
}
dda->live = (step_option & (X_CAN_STEP | Y_CAN_STEP | Z_CAN_STEP | E_CAN_STEP | F_CAN_STEP));
}

View File

@ -6,25 +6,25 @@
#include "target.h"
#include "pinout.h"
#include "gcode.h"
#include "machine.h"
typedef struct {
TARGET currentpoint;
TARGET endpoint;
uint8_t steep :1;
uint8_t swap :1;
uint8_t x_direction :1;
uint8_t y_direction :1;
uint8_t z_direction :1;
uint8_t e_direction :1;
uint8_t f_direction :1;
uint8_t nullmove :1;
uint8_t live :1;
int8_t x_delta;
int8_t y_delta;
int8_t z_delta;
int8_t e_delta;
int8_t f_delta;
int16_t x_delta;
int16_t y_delta;
int16_t z_delta;
int16_t e_delta;
int16_t f_delta;
int32_t x_counter;
int32_t y_counter;
@ -36,8 +36,13 @@ typedef struct {
uint16_t f_scale;
uint32_t distance;
uint32_t move_duration;
} DDA;
extern uint8_t mb_head;
extern uint8_t mb_tail;
extern DDA movebuffer[MOVEBUFFER_SIZE];
uint32_t approx_distance( int32_t dx, int32_t dy );
void dda_create(GCODE_COMMAND *cmd, DDA *dda);

View File

@ -5,9 +5,6 @@
#include "machine.h"
#include "dda.h"
extern uint8_t mb_head;
extern uint8_t mb_tail;
extern DDA movebuffer[16];
extern uint8_t option_bitfield;
#define PI 3.1415926535
@ -135,7 +132,7 @@ void scan_char(uint8_t c) {
else if ((c == '.') && ((exp & 0x7F) == 0))
exp |= 1;
else if (c >= '0' && c <= '9') {
mantissa = (mantissa * 10) + (c - '0');
mantissa = ((mantissa << 3) + (mantissa << 1)) + (c - '0');
if (exp & 0x7F)
exp++;
}
@ -189,6 +186,6 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
}
if (do_move) {
dda_create(gcmd, movebuffer);
dda_create(&gcmd->target, movebuffer);
}
}

View File

@ -4,9 +4,7 @@
/*
machine variables
*/
#define AXIS_COUNT 5
#define AXIS_HOMING_COUNT 3
#define MOVEBUFFER_SIZE 8
/*
axis calculations, adjust as necessary
*/

View File

@ -9,13 +9,10 @@
#include "dda.h"
#include "gcode.h"
#include "timer.h"
#include "machine.h"
uint8_t mb_head = 0;
uint8_t mb_tail = 0;
DDA movebuffer[16];
uint8_t option_bitfield;
struct {
@ -31,6 +28,9 @@ int main (void)
// set up serial
serial_init();
// set up timers
setupTimerInterrupt();
// enable interrupts
sei();

View File

@ -1,48 +0,0 @@
#include "pinout.h"
void delayMicrosecondsInterruptible(uint16_t us)
{
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
// busy wait
__asm__ __volatile__ ("1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" :
"=w" (us) :
"0" (us) // 2 cycles
);
}
void x_step() {
WRITE(DIO0, 1);
delayMicrosecondsInterruptible(5);
WRITE(DIO0, 0);
}
void y_step() {
WRITE(DIO4, 1);
delayMicrosecondsInterruptible(5);
WRITE(DIO4, 0);
}
void z_step() {
WRITE(DIO8, 1);
delayMicrosecondsInterruptible(5);
WRITE(DIO8, 0);
}
void e_step() {
WRITE(DIO12, 1);
delayMicrosecondsInterruptible(5);
WRITE(DIO12, 0);
}

View File

@ -7,74 +7,59 @@
#define MASK(PIN) (1 << PIN)
#endif
#define _PIN(P) #P
#define READ(IO) (RPORT_ ## IO & MASK(PIN_ ## IO))
#define WRITE(IO, v) if (v) { WPORT_ ## IO |= MASK(PIN_ ## IO); } else { WPORT_ ## IO &= ~MASK(PIN_ ## IO); }
#define SET_INPUT(IO) (DDR_ ## IO |= MASK(PIN_ ## IO))
#define SET_OUTPUT(IO) (DDR_ ## IO &= ~MASK(PIN ## IO))
// #define X_STEP_PIN DIO0
// #define X_DIR_PIN DIO1
// #define X_MIN_MIN DIO2
// #define X_MAX_PIN DIO3
// void x_step(void);
// void y_step(void);
// void z_step(void);
// void e_step(void);
// #define Y_STEP_PIN DIO4
// #define Y_DIR_PIN DIO5
// #define Y_MIN_MIN DIO6
// #define Y_MAX_PIN DIO7
#define _x_step(st) WRITE(AIO0, st)
#define x_step() _x_step(1);
#define x_direction(dir) WRITE(AIO1, dir)
#define x_min() READ(AIO2)
#ifdef MAX_ENDSTOPS
#define x_max() READ(AIO3)
#else
#define x_max() (0)
#endif
// #define Z_STEP_PIN DIO8
// #define Z_DIR_PIN DIO9
// #define Z_MIN_MIN DIO10
// #define Z_MAX_PIN DIO11
#define _y_step(st) WRITE(DIO2, st)
#define y_step() _y_step(1);
#define y_direction(dir) WRITE(DIO3, dir)
#define y_min() READ(DIO4)
#ifdef MAX_ENDSTOPS
#define y_max() READ(DIO5)
#else
#define y_max() (0)
#endif
// #define E_STEP_PIN DIO12
// #define E_DIR_PIN DIO13
#define _z_step(st) WRITE(DIO6, st)
#define z_step() _z_step(1);
#define z_direction(dir) WRITE(DIO7, dir)
#define z_min() READ(DIO8)
#ifdef MAX_ENDSTOPS
#define z_max() READ(DIO9)
#else
#define z_max() (0)
#endif
void x_step(void);
void y_step(void);
void z_step(void);
void e_step(void);
#define _e_step(st) WRITE(AIO4, st)
#define e_step() _e_step(1);
#define e_direction(dir) WRITE(AIO5, dir)
inline void x_direction(uint8_t dir) {
WRITE(DIO1, dir);
}
#define enable_steppers() WRITE(DIO10, 1)
#define disable_steppers() WRITE(DIO10, 0)
inline uint8_t x_min(void) {
return READ(DIO2);
}
inline uint8_t x_max(void) {
return READ(DIO3);
}
inline void y_direction(uint8_t dir) {
WRITE(DIO5, dir);
}
inline uint8_t y_min(void) {
return READ(DIO6);
}
inline uint8_t y_max(void) {
return READ(DIO7);
}
inline void z_direction(uint8_t dir) {
WRITE(DIO9, dir);
}
inline uint8_t z_min(void) {
return READ(DIO10);
}
inline uint8_t z_max(void) {
return READ(DIO11);
}
inline void e_direction(uint8_t dir) {
WRITE(DIO13, dir);
inline void unstep(void) {
_x_step(0);
_y_step(0);
_z_step(0);
_e_step(0);
}
#endif /* _PINOUT_H */

158
mendel/timer.c Normal file
View File

@ -0,0 +1,158 @@
#include "timer.h"
#include <avr/interrupt.h>
#include "pinout.h"
#include "dda.h"
ISR(TIMER1_COMPA_vect) {
// static interruptBlink = 0;
//
// interruptBlink++;
// if (interruptBlink == 0x80) {
// blink();
// interruptBlink = 0;
// }
if(movebuffer[mb_tail].live)
dda_step(&movebuffer[mb_tail]);
else
next_move();
}
void setupTimerInterrupt()
{
//clear the registers
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
TIMSK1 = 0;
//waveform generation = 0100 = CTC
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1A &= ~(1<<WGM11);
TCCR1A &= ~(1<<WGM10);
//output mode = 00 (disconnected)
TCCR1A &= ~(1<<COM1A1);
TCCR1A &= ~(1<<COM1A0);
TCCR1A &= ~(1<<COM1B1);
TCCR1A &= ~(1<<COM1B0);
//start off with a slow frequency.
setTimerResolution(4);
setTimerCeiling(65535);
}
uint8_t getTimerResolution(const uint32_t delay)
{
// these also represent frequency: 1000000 / delay / 2 = frequency in hz.
// our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs (4 millisecond max))
// range: 8Mhz max - 122hz min
if (delay <= 65535L)
return 0;
// our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs (32 millisecond max))
// range:1Mhz max - 15.26hz min
else if (delay <= 524280L)
return 1;
// our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs (0.26 seconds max))
// range: 125Khz max - 1.9hz min
else if (delay <= 4194240L)
return 2;
// our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs (1.04 seconds max))
// range: 31.25Khz max - 0.475hz min
else if (delay <= 16776960L)
return 3;
// our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs (4.19 seconds max))
// range: 7.812Khz max - 0.119hz min
// else if (delay <= 67107840L)
// return 4;
//its really slow... hopefully we can just get by with super slow.
// else
return 4;
}
void setTimerResolution(uint8_t r)
{
//here's how you figure out the tick size:
// 1000000 / ((F_CPU / prescaler))
// 1000000 = microseconds in 1 second
// prescaler = your prescaler
// assuming CS10,CS11,CS12 are adjacent bits in platform endian order,
TCCR1B = (TCCR1B & ~(MASK(CS10) | MASK(CS11) | MASK(CS12))) | ((r + 1) << CS10);
}
uint16_t getTimerCeiling(const uint32_t delay)
{
// our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs)
if (delay <= 65535L)
return (delay & 0xffff);
// our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs)
else if (delay <= 524280L)
return ((delay >> 3) & 0xffff);
// our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs)
else if (delay <= 4194240L)
return ((delay >> 6) & 0xffff);
// our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs)
else if (delay <= 16776960L)
return ((delay >> 8) & 0xffff);
// our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs)
else if (delay <= 67107840L)
return ((delay >> 10) & 0xffff);
//its really slow... hopefully we can just get by with super slow.
else
return 65535;
}
// Depending on how much work the interrupt function has to do, this is
// pretty accurate between 10 us and 0.1 s. At fast speeds, the time
// taken in the interrupt function becomes significant, of course.
// Note - it is up to the user to call enableTimerInterrupt() after a call
// to this function.
void setTimer(uint32_t delay)
{
// delay is the delay between steps in microsecond ticks.
//
// we break it into 5 different resolutions based on the delay.
// then we set the resolution based on the size of the delay.
// we also then calculate the timer ceiling required. (ie what the counter counts to)
// the result is the timer counts up to the appropriate time and then fires an interrupt.
// Actual ticks are 0.0625 us, so multiply delay by 16
// convert to ticks
delay = delay US;
setTimerCeiling(getTimerCeiling(delay));
setTimerResolution(getTimerResolution(delay));
}
// from reprap project 5D firmware
void delayMicrosecondsInterruptible(uint16_t us)
{
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
// busy wait
__asm__ __volatile__ ("1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" :
"=w" (us) :
"0" (us) // 2 cycles
);
}

37
mendel/timer.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef _TIMER_H
#define _TIMER_H
#include <stdint.h>
#include <avr/io.h>
// time-related constants
#define US * (F_CPU / 1000000)
#define MS * (F_CPU / 1000)
#define DEFAULT_TICK (100 US)
void setupTimerInterrupt(void);
uint8_t getTimerResolution(const uint32_t delay);
void setTimerResolution(uint8_t r);
uint16_t getTimerCeiling(const uint32_t delay);
void setTimer(uint32_t delay);
void delayMicrosecondsInterruptible(unsigned int us);
inline void enableTimerInterrupt(void)
{
TIMSK1 |= (1<<OCIE1A);
}
inline void disableTimerInterrupt(void)
{
TIMSK1 &= ~(1<<OCIE1A);
}
inline void setTimerCeiling(uint16_t c)
{
OCR1A = c;
}
#endif /* _TIMER_H */