tons of commenting and tidying, fixes to heater PID loop
This commit is contained in:
parent
8cc6fa6937
commit
4c47901b66
|
|
@ -11,6 +11,12 @@
|
||||||
#define MASK(PIN) (1 << PIN)
|
#define MASK(PIN) (1 << PIN)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
magic I/O routines
|
||||||
|
|
||||||
|
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
|
||||||
|
*/
|
||||||
|
|
||||||
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
|
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
|
||||||
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
|
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
|
||||||
#define _TOGGLE(IO) (IO ## _RPORT = MASK(IO ## _PIN))
|
#define _TOGGLE(IO) (IO ## _RPORT = MASK(IO ## _PIN))
|
||||||
|
|
@ -33,6 +39,10 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ports and functions
|
ports and functions
|
||||||
|
|
||||||
|
added as necessary or if I feel like it- not a comprehensive list!
|
||||||
|
|
||||||
|
probably needs some #ifdefs for various chip types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// UART
|
// UART
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ volatile uint32_t clock = 0;
|
||||||
|
|
||||||
// 1/4 second tick
|
// 1/4 second tick
|
||||||
uint8_t clock_counter_250ms = 0;
|
uint8_t clock_counter_250ms = 0;
|
||||||
volatile uint8_t clock_flag_250ms = 0;
|
uint8_t clock_counter_1s = 0;
|
||||||
|
volatile uint8_t clock_flag = 0;
|
||||||
|
|
||||||
void clock_setup() {
|
void clock_setup() {
|
||||||
// use system clock
|
// use system clock
|
||||||
|
|
@ -39,17 +40,19 @@ void clock_setup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ISR(TIMER2_COMPA_vect) {
|
ISR(TIMER2_COMPA_vect) {
|
||||||
// WRITE(SCK, 0);
|
|
||||||
// global clock
|
// global clock
|
||||||
#ifdef GLOBAL_CLOCK
|
#ifdef GLOBAL_CLOCK
|
||||||
clock++;
|
clock++;
|
||||||
#endif
|
#endif
|
||||||
// 1/4 second tick
|
// 1/4 second tick
|
||||||
if (++clock_counter_250ms == 250) {
|
if (++clock_counter_250ms == 250) {
|
||||||
clock_flag_250ms = 255;
|
clock_flag |= CLOCK_FLAG_250MS;
|
||||||
clock_counter_250ms = 0;
|
clock_counter_250ms = 0;
|
||||||
|
if (++clock_counter_1s == 4) {
|
||||||
|
clock_flag |= CLOCK_FLAG_1S;
|
||||||
|
clock_counter_1s = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// WRITE(SCK, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GLOBAL_CLOCK
|
#ifdef GLOBAL_CLOCK
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,24 @@ void clock_setup(void);
|
||||||
uint32_t clock_read(void);
|
uint32_t clock_read(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern volatile uint8_t clock_flag_250ms;
|
extern volatile uint8_t clock_flag;
|
||||||
|
|
||||||
#define CLOCK_FLAG_250MS 1
|
#define CLOCK_FLAG_250MS 1
|
||||||
// #define CLOCK_FLAG_250MS_TEMPCHECK 1
|
#define CLOCK_FLAG_1S 2
|
||||||
// #define CLOCK_FLAG_250MS_REPORT 2
|
|
||||||
// #define CLOCK_FLAG_250MS_STEPTIMEOUT 4
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ifclock() {}
|
ifclock() {}
|
||||||
|
|
||||||
so we can do stuff like:
|
so we can do stuff like:
|
||||||
ifclock(CLOCK_FLAG_250MS_REPORT) {
|
ifclock(CLOCK_FLAG_250MS) {
|
||||||
report();
|
report();
|
||||||
}
|
}
|
||||||
|
|
||||||
or:
|
or:
|
||||||
ifclock(CLOCK_FLAG_250MS_STEPTIMEOUT)
|
ifclock(CLOCK_FLAG_1S)
|
||||||
disable_steppers();
|
disable_steppers();
|
||||||
*/
|
*/
|
||||||
#define ifclock(F) for (;clock_flag_250ms & (F);clock_flag_250ms &= ~(F))
|
|
||||||
|
#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F))
|
||||||
|
|
||||||
#endif /* _CLOCK_H */
|
#endif /* _CLOCK_H */
|
||||||
|
|
|
||||||
232
mendel/dda.c
232
mendel/dda.c
|
|
@ -174,25 +174,6 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
serwrite_uint32(dda->total_steps); serial_writechar(',');
|
serwrite_uint32(dda->total_steps); serial_writechar(',');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (dda->f_delta > dda->total_steps) {
|
|
||||||
// dda->f_scale = dda->f_delta / dda->total_steps;
|
|
||||||
// if (dda->f_scale > 3) {
|
|
||||||
// dda->f_delta = dda->total_steps;
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// // if we boost the number of steps here, many will only be F-steps which take no time- maybe we should calculate move_distance first?
|
|
||||||
// dda->f_scale = 1;
|
|
||||||
// dda->total_steps = dda->f_delta;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// dda->f_scale = 1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (DEBUG) {
|
|
||||||
// serwrite_uint32(dda->total_steps); serial_writechar(',');
|
|
||||||
// }
|
|
||||||
|
|
||||||
dda->x_counter = dda->y_counter = dda->z_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);
|
-(dda->total_steps >> 1);
|
||||||
|
|
||||||
|
|
@ -206,8 +187,6 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
|
|
||||||
if (distance < 2)
|
if (distance < 2)
|
||||||
distance = dda->e_delta * UM_PER_STEP_E;
|
distance = dda->e_delta * UM_PER_STEP_E;
|
||||||
// if (distance < 2)
|
|
||||||
// distance = dda->f_delta;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
serwrite_uint32(distance); serial_writechar(',');
|
serwrite_uint32(distance); serial_writechar(',');
|
||||||
|
|
@ -241,12 +220,6 @@ void dda_create(DDA *dda, TARGET *target) {
|
||||||
|
|
||||||
void dda_start(DDA *dda) {
|
void dda_start(DDA *dda) {
|
||||||
// called from interrupt context: keep it simple!
|
// called from interrupt context: keep it simple!
|
||||||
// if (
|
|
||||||
// (current_position.X == dda->endpoint.X) &&
|
|
||||||
// (current_position.Y == dda->endpoint.Y) &&
|
|
||||||
// (current_position.Z == dda->endpoint.Z) &&
|
|
||||||
// (current_position.E == dda->endpoint.E)
|
|
||||||
// ) {
|
|
||||||
if (dda->nullmove) {
|
if (dda->nullmove) {
|
||||||
// just change speed?
|
// just change speed?
|
||||||
current_position.F = dda->endpoint.F;
|
current_position.F = dda->endpoint.F;
|
||||||
|
|
@ -310,123 +283,110 @@ void dda_step(DDA *dda) {
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
serial_writechar('!');
|
serial_writechar('!');
|
||||||
|
|
||||||
// turn 'L' light OFF so it's obvious if we froze in this routine
|
step_option &= ~(X_CAN_STEP | Y_CAN_STEP | Z_CAN_STEP | E_CAN_STEP | F_CAN_STEP);
|
||||||
// if (DEBUG)
|
|
||||||
// WRITE(SCK, 0);
|
|
||||||
|
|
||||||
// do {
|
|
||||||
// WRITE(SCK, 0);
|
|
||||||
|
|
||||||
step_option &= ~(X_CAN_STEP | Y_CAN_STEP | Z_CAN_STEP | E_CAN_STEP | F_CAN_STEP);
|
|
||||||
// step_option |= can_step(x_min(), x_max(), current_position.X, dda->endpoint.X, dda->x_direction) & X_CAN_STEP;
|
// 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(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(z_min(), z_max(), current_position.Z, dda->endpoint.Z, dda->z_direction) & Z_CAN_STEP;
|
||||||
step_option |= can_step(0 , 0 , current_position.X, dda->endpoint.X, dda->x_direction) & X_CAN_STEP;
|
step_option |= can_step(0 , 0 , current_position.X, dda->endpoint.X, dda->x_direction) & X_CAN_STEP;
|
||||||
step_option |= can_step(0 , 0 , current_position.Y, dda->endpoint.Y, dda->y_direction) & Y_CAN_STEP;
|
step_option |= can_step(0 , 0 , current_position.Y, dda->endpoint.Y, dda->y_direction) & Y_CAN_STEP;
|
||||||
step_option |= can_step(0 , 0 , current_position.Z, dda->endpoint.Z, dda->z_direction) & Z_CAN_STEP;
|
step_option |= can_step(0 , 0 , current_position.Z, dda->endpoint.Z, dda->z_direction) & Z_CAN_STEP;
|
||||||
step_option |= can_step(0 , 0 , current_position.E, dda->endpoint.E, dda->e_direction) & E_CAN_STEP;
|
step_option |= can_step(0 , 0 , current_position.E, dda->endpoint.E, dda->e_direction) & E_CAN_STEP;
|
||||||
step_option |= can_step(0 , 0 , current_position.F, dda->endpoint.F, dda->f_direction) & F_CAN_STEP;
|
step_option |= can_step(0 , 0 , current_position.F, dda->endpoint.F, dda->f_direction) & F_CAN_STEP;
|
||||||
|
|
||||||
if (step_option & X_CAN_STEP) {
|
if (step_option & X_CAN_STEP) {
|
||||||
dda->x_counter -= dda->x_delta;
|
dda->x_counter -= dda->x_delta;
|
||||||
if (dda->x_counter < 0) {
|
if (dda->x_counter < 0) {
|
||||||
step_option |= REAL_MOVE;
|
step_option |= REAL_MOVE;
|
||||||
|
|
||||||
x_step();
|
x_step();
|
||||||
if (dda->x_direction)
|
if (dda->x_direction)
|
||||||
current_position.X++;
|
current_position.X++;
|
||||||
else
|
else
|
||||||
current_position.X--;
|
current_position.X--;
|
||||||
|
|
||||||
dda->x_counter += dda->total_steps;
|
dda->x_counter += dda->total_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_option & Y_CAN_STEP) {
|
||||||
|
dda->y_counter -= dda->y_delta;
|
||||||
|
if (dda->y_counter < 0) {
|
||||||
|
step_option |= REAL_MOVE;
|
||||||
|
|
||||||
|
y_step();
|
||||||
|
if (dda->y_direction)
|
||||||
|
current_position.Y++;
|
||||||
|
else
|
||||||
|
current_position.Y--;
|
||||||
|
|
||||||
|
dda->y_counter += dda->total_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_option & Z_CAN_STEP) {
|
||||||
|
dda->z_counter -= dda->z_delta;
|
||||||
|
if (dda->z_counter < 0) {
|
||||||
|
step_option |= REAL_MOVE;
|
||||||
|
|
||||||
|
z_step();
|
||||||
|
if (dda->z_direction)
|
||||||
|
current_position.Z++;
|
||||||
|
else
|
||||||
|
current_position.Z--;
|
||||||
|
|
||||||
|
dda->z_counter += dda->total_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_option & E_CAN_STEP) {
|
||||||
|
dda->e_counter -= dda->e_delta;
|
||||||
|
if (dda->e_counter < 0) {
|
||||||
|
step_option |= REAL_MOVE;
|
||||||
|
|
||||||
|
e_step();
|
||||||
|
if (dda->e_direction)
|
||||||
|
current_position.E++;
|
||||||
|
else
|
||||||
|
current_position.E--;
|
||||||
|
|
||||||
|
dda->e_counter += dda->total_steps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step_option & F_CAN_STEP) {
|
||||||
|
dda->f_counter -= dda->f_delta;
|
||||||
|
// since we don't allow total_steps to be defined by F, we may need to step multiple times if f_delta is greater than total_steps
|
||||||
|
while (dda->f_counter < 0) {
|
||||||
|
|
||||||
|
dda->f_counter += dda->total_steps;
|
||||||
|
|
||||||
|
if (dda->f_direction) {
|
||||||
|
current_position.F += 1;
|
||||||
|
if (current_position.F > dda->endpoint.F)
|
||||||
|
current_position.F = dda->endpoint.F;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
current_position.F -= 1;
|
||||||
if (step_option & Y_CAN_STEP) {
|
if (current_position.F < dda->endpoint.F)
|
||||||
dda->y_counter -= dda->y_delta;
|
current_position.F = dda->endpoint.F;
|
||||||
if (dda->y_counter < 0) {
|
|
||||||
step_option |= REAL_MOVE;
|
|
||||||
|
|
||||||
y_step();
|
|
||||||
if (dda->y_direction)
|
|
||||||
current_position.Y++;
|
|
||||||
else
|
|
||||||
current_position.Y--;
|
|
||||||
|
|
||||||
dda->y_counter += dda->total_steps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
step_option |= F_REAL_STEP;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (step_option & Z_CAN_STEP) {
|
// this generates too much debug output for all but the slowest step rates
|
||||||
dda->z_counter -= dda->z_delta;
|
if (0 && DEBUG) {
|
||||||
if (dda->z_counter < 0) {
|
serial_writechar('[');
|
||||||
step_option |= REAL_MOVE;
|
serwrite_hex8(step_option);
|
||||||
|
serial_writechar(':');
|
||||||
z_step();
|
serwrite_int32(current_position.F);
|
||||||
if (dda->z_direction)
|
serial_writechar('/');
|
||||||
current_position.Z++;
|
serwrite_int32(dda->endpoint.F);
|
||||||
else
|
serial_writechar('#');
|
||||||
current_position.Z--;
|
serwrite_uint32(dda->move_duration);
|
||||||
|
serial_writechar(']');
|
||||||
dda->z_counter += dda->total_steps;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_option & E_CAN_STEP) {
|
|
||||||
dda->e_counter -= dda->e_delta;
|
|
||||||
if (dda->e_counter < 0) {
|
|
||||||
step_option |= REAL_MOVE;
|
|
||||||
|
|
||||||
e_step();
|
|
||||||
if (dda->e_direction)
|
|
||||||
current_position.E++;
|
|
||||||
else
|
|
||||||
current_position.E--;
|
|
||||||
|
|
||||||
dda->e_counter += dda->total_steps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (step_option & F_CAN_STEP) {
|
|
||||||
dda->f_counter -= dda->f_delta;
|
|
||||||
// since we don't allow total_steps to be defined by F, we may need to step multiple times if f_delta is greater than total_steps
|
|
||||||
while (dda->f_counter < 0) {
|
|
||||||
|
|
||||||
dda->f_counter += dda->total_steps;
|
|
||||||
|
|
||||||
if (dda->f_direction) {
|
|
||||||
current_position.F += 1;
|
|
||||||
if (current_position.F > dda->endpoint.F)
|
|
||||||
current_position.F = dda->endpoint.F;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
current_position.F -= 1;
|
|
||||||
if (current_position.F < dda->endpoint.F)
|
|
||||||
current_position.F = dda->endpoint.F;
|
|
||||||
}
|
|
||||||
|
|
||||||
step_option |= F_REAL_STEP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this generates too much debug output for all but the slowest step rates
|
|
||||||
if (0 && DEBUG) {
|
|
||||||
serial_writechar('[');
|
|
||||||
serwrite_hex8(step_option);
|
|
||||||
serial_writechar(':');
|
|
||||||
serwrite_int32(current_position.F);
|
|
||||||
serial_writechar('/');
|
|
||||||
serwrite_int32(dda->endpoint.F);
|
|
||||||
serial_writechar('#');
|
|
||||||
serwrite_uint32(dda->move_duration);
|
|
||||||
serial_writechar(']');
|
|
||||||
}
|
|
||||||
|
|
||||||
// WRITE(SCK, 1);
|
|
||||||
|
|
||||||
// } while ( ((step_option & REAL_MOVE ) == 0) &&
|
|
||||||
// ((step_option & F_CAN_STEP) != 0) );
|
|
||||||
// } while (0);
|
|
||||||
|
|
||||||
if (step_option & REAL_MOVE)
|
if (step_option & REAL_MOVE)
|
||||||
// we stepped, reset timeout
|
// we stepped, reset timeout
|
||||||
|
|
@ -453,8 +413,4 @@ void dda_step(DDA *dda) {
|
||||||
// turn off step outputs, hopefully they've been on long enough by now to register with the drivers
|
// turn off step outputs, hopefully they've been on long enough by now to register with the drivers
|
||||||
// if not, too bad. or insert a (very!) small delay here, or fire up a spare timer or something
|
// if not, too bad. or insert a (very!) small delay here, or fire up a spare timer or something
|
||||||
unstep();
|
unstep();
|
||||||
|
|
||||||
// turn 'L' light back on again
|
|
||||||
// if (DEBUG)
|
|
||||||
// WRITE(SCK, 1);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
types
|
types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// target is simply a point in space/time
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t X;
|
int32_t X;
|
||||||
int32_t Y;
|
int32_t Y;
|
||||||
|
|
@ -18,8 +19,8 @@ typedef struct {
|
||||||
uint32_t F;
|
uint32_t F;
|
||||||
} TARGET;
|
} TARGET;
|
||||||
|
|
||||||
|
// this is a digital differential analyser data struct, holding both the initial values and the counters as it progresses
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// TARGET currentpoint;
|
|
||||||
TARGET endpoint;
|
TARGET endpoint;
|
||||||
|
|
||||||
uint8_t x_direction :1;
|
uint8_t x_direction :1;
|
||||||
|
|
@ -51,9 +52,13 @@ typedef struct {
|
||||||
variables
|
variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// steptimeout is set to zero when we step, and increases over time so we can turn the motors off when they've been idle for a while
|
||||||
extern uint8_t steptimeout;
|
extern uint8_t steptimeout;
|
||||||
|
|
||||||
|
// startpoint holds the end position of the most recently created DDA, so we know where the next one starts
|
||||||
extern TARGET startpoint;
|
extern TARGET startpoint;
|
||||||
|
|
||||||
|
// current_position holds the machine's current position. this is only updated when we step, or when G92 (set home) is received.
|
||||||
extern TARGET current_position;
|
extern TARGET current_position;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ uint8_t mb_head = 0;
|
||||||
uint8_t mb_tail = 0;
|
uint8_t mb_tail = 0;
|
||||||
DDA movebuffer[MOVEBUFFER_SIZE];
|
DDA movebuffer[MOVEBUFFER_SIZE];
|
||||||
|
|
||||||
|
|
||||||
uint8_t queue_full() {
|
uint8_t queue_full() {
|
||||||
if (mb_tail == 0)
|
if (mb_tail == 0)
|
||||||
return mb_head == (MOVEBUFFER_SIZE - 1);
|
return mb_head == (MOVEBUFFER_SIZE - 1);
|
||||||
|
|
@ -21,6 +20,7 @@ uint8_t queue_empty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void enqueue(TARGET *t) {
|
void enqueue(TARGET *t) {
|
||||||
|
// don't call this function when the queue is full, but just in case, wait for a move to complete and free up the space for the passed target
|
||||||
while (queue_full())
|
while (queue_full())
|
||||||
delay(WAITING_DELAY);
|
delay(WAITING_DELAY);
|
||||||
|
|
||||||
|
|
@ -31,24 +31,24 @@ void enqueue(TARGET *t) {
|
||||||
|
|
||||||
dda_create(&movebuffer[h], t);
|
dda_create(&movebuffer[h], t);
|
||||||
|
|
||||||
// if queue only has one space left, stop transmition
|
|
||||||
if (((h + 2) & (MOVEBUFFER_SIZE - 1)) == mb_tail)
|
|
||||||
xoff();
|
|
||||||
|
|
||||||
mb_head = h;
|
mb_head = h;
|
||||||
|
|
||||||
|
#ifdef XONXOFF
|
||||||
|
// if queue is full, stop transmition
|
||||||
|
if (queue_full())
|
||||||
|
xoff();
|
||||||
|
#endif
|
||||||
|
|
||||||
// fire up in case we're not running yet
|
// fire up in case we're not running yet
|
||||||
enableTimerInterrupt();
|
enableTimerInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void next_move() {
|
void next_move() {
|
||||||
if (queue_empty()) {
|
if (queue_empty()) {
|
||||||
// queue is empty
|
|
||||||
// disable_steppers();
|
|
||||||
// setTimer(DEFAULT_TICK);
|
|
||||||
disableTimerInterrupt();
|
disableTimerInterrupt();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// next item
|
||||||
uint8_t t = mb_tail;
|
uint8_t t = mb_tail;
|
||||||
t++;
|
t++;
|
||||||
if (t == MOVEBUFFER_SIZE)
|
if (t == MOVEBUFFER_SIZE)
|
||||||
|
|
@ -56,8 +56,11 @@ void next_move() {
|
||||||
dda_start(&movebuffer[t]);
|
dda_start(&movebuffer[t]);
|
||||||
mb_tail = t;
|
mb_tail = t;
|
||||||
}
|
}
|
||||||
// restart transmission
|
|
||||||
xon();
|
#ifdef XONXOFF
|
||||||
|
// restart transmission
|
||||||
|
xon();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_queue() {
|
void print_queue() {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
variables
|
variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// this is the ringbuffer that holds the current and pending moves.
|
||||||
extern uint8_t mb_head;
|
extern uint8_t mb_head;
|
||||||
extern uint8_t mb_tail;
|
extern uint8_t mb_tail;
|
||||||
extern DDA movebuffer[MOVEBUFFER_SIZE];
|
extern DDA movebuffer[MOVEBUFFER_SIZE];
|
||||||
|
|
@ -15,10 +16,17 @@ extern DDA movebuffer[MOVEBUFFER_SIZE];
|
||||||
methods
|
methods
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// queue status methods
|
||||||
uint8_t queue_full(void);
|
uint8_t queue_full(void);
|
||||||
uint8_t queue_empty(void);
|
uint8_t queue_empty(void);
|
||||||
|
|
||||||
|
// add a new target to the queue
|
||||||
void enqueue(TARGET *t);
|
void enqueue(TARGET *t);
|
||||||
|
|
||||||
|
// called from step timer when current move is complete
|
||||||
void next_move(void);
|
void next_move(void);
|
||||||
|
|
||||||
|
// print queue status
|
||||||
void print_queue(void);
|
void print_queue(void);
|
||||||
|
|
||||||
#endif /* _DDA_QUEUE */
|
#endif /* _DDA_QUEUE */
|
||||||
|
|
|
||||||
119
mendel/gcode.c
119
mendel/gcode.c
|
|
@ -69,6 +69,10 @@ int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public functions
|
||||||
|
*/
|
||||||
|
|
||||||
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f) {
|
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f) {
|
||||||
TARGET t = startpoint;
|
TARGET t = startpoint;
|
||||||
t.X = x;
|
t.X = x;
|
||||||
|
|
@ -91,10 +95,6 @@ void SpecialMoveE(int32_t e, uint32_t f) {
|
||||||
enqueue(&t);
|
enqueue(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
public functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
void scan_char(uint8_t c) {
|
void scan_char(uint8_t c) {
|
||||||
static uint8_t last_field = 0;
|
static uint8_t last_field = 0;
|
||||||
|
|
||||||
|
|
@ -102,38 +102,61 @@ void scan_char(uint8_t c) {
|
||||||
if (c >= 'a' && c <= 'z')
|
if (c >= 'a' && c <= 'z')
|
||||||
c &= ~32;
|
c &= ~32;
|
||||||
|
|
||||||
// process field
|
// process previous field
|
||||||
if (last_field) {
|
if (last_field) {
|
||||||
|
// check if we're seeing a new field or end of line
|
||||||
if ((indexof(c, alphabet) >= 0) || (c == 10)) {
|
if ((indexof(c, alphabet) >= 0) || (c == 10)) {
|
||||||
switch (last_field) {
|
switch (last_field) {
|
||||||
case 'G':
|
case 'G':
|
||||||
next_target.G = read_digit.mantissa;
|
next_target.G = read_digit.mantissa;
|
||||||
serwrite_uint8(next_target.G);
|
if (DEBUG)
|
||||||
|
serwrite_uint8(next_target.G);
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
next_target.M = read_digit.mantissa;
|
next_target.M = read_digit.mantissa;
|
||||||
serwrite_uint8(next_target.M);
|
if (DEBUG)
|
||||||
|
serwrite_uint8(next_target.M);
|
||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
next_target.target.X = decfloat_to_int(&read_digit, STEPS_PER_MM_X, 1);
|
if (next_target.option_inches)
|
||||||
serwrite_int32(next_target.target.X);
|
next_target.target.X = decfloat_to_int(&read_digit, STEPS_PER_IN_X, 1);
|
||||||
|
else
|
||||||
|
next_target.target.X = decfloat_to_int(&read_digit, STEPS_PER_MM_X, 1);
|
||||||
|
if (DEBUG)
|
||||||
|
serwrite_int32(next_target.target.X);
|
||||||
break;
|
break;
|
||||||
case 'Y':
|
case 'Y':
|
||||||
next_target.target.Y = decfloat_to_int(&read_digit, STEPS_PER_MM_Y, 1);
|
if (next_target.option_inches)
|
||||||
serwrite_int32(next_target.target.Y);
|
next_target.target.Y = decfloat_to_int(&read_digit, STEPS_PER_IN_Y, 1);
|
||||||
|
else
|
||||||
|
next_target.target.Y = decfloat_to_int(&read_digit, STEPS_PER_MM_Y, 1);
|
||||||
|
if (DEBUG)
|
||||||
|
serwrite_int32(next_target.target.Y);
|
||||||
break;
|
break;
|
||||||
case 'Z':
|
case 'Z':
|
||||||
next_target.target.Z = decfloat_to_int(&read_digit, STEPS_PER_MM_Z, 1);
|
if (next_target.option_inches)
|
||||||
serwrite_int32(next_target.target.Z);
|
next_target.target.Z = decfloat_to_int(&read_digit, STEPS_PER_IN_Z, 1);
|
||||||
|
else
|
||||||
|
next_target.target.Z = decfloat_to_int(&read_digit, STEPS_PER_MM_Z, 1);
|
||||||
|
if (DEBUG)
|
||||||
|
serwrite_int32(next_target.target.Z);
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
next_target.target.E = decfloat_to_int(&read_digit, STEPS_PER_MM_E, 1);
|
if (next_target.option_inches)
|
||||||
serwrite_uint32(next_target.target.E);
|
next_target.target.E = decfloat_to_int(&read_digit, STEPS_PER_IN_E, 1);
|
||||||
|
else
|
||||||
|
next_target.target.E = decfloat_to_int(&read_digit, STEPS_PER_MM_E, 1);
|
||||||
|
if (DEBUG)
|
||||||
|
serwrite_uint32(next_target.target.E);
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
// just use raw integer, we need move distance and n_steps to convert it to a useful value, so wait until we have those to convert it
|
// just use raw integer, we need move distance and n_steps to convert it to a useful value, so wait until we have those to convert it
|
||||||
next_target.target.F = decfloat_to_int(&read_digit, 1, 1);
|
if (next_target.option_inches)
|
||||||
serwrite_uint32(next_target.target.F);
|
next_target.target.F = decfloat_to_int(&read_digit, 254, 10);
|
||||||
|
else
|
||||||
|
next_target.target.F = decfloat_to_int(&read_digit, 1, 1);
|
||||||
|
if (DEBUG)
|
||||||
|
serwrite_uint32(next_target.target.F);
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
// if this is temperature, multiply by 4 to convert to quarter-degree units
|
// if this is temperature, multiply by 4 to convert to quarter-degree units
|
||||||
|
|
@ -141,9 +164,13 @@ void scan_char(uint8_t c) {
|
||||||
// but it takes less code, less memory and loses no precision if we do it here instead
|
// but it takes less code, less memory and loses no precision if we do it here instead
|
||||||
if (next_target.M == 104)
|
if (next_target.M == 104)
|
||||||
next_target.S = decfloat_to_int(&read_digit, 4, 1);
|
next_target.S = decfloat_to_int(&read_digit, 4, 1);
|
||||||
|
// if this is heater PID stuff, multiply by PID_SCALE because we divide by PID_SCALE later on
|
||||||
|
else if ((next_target.M >= 130) && (next_target.M <= 132))
|
||||||
|
next_target.S = decfloat_to_int(&read_digit, PID_SCALE, 1);
|
||||||
else
|
else
|
||||||
next_target.S = decfloat_to_int(&read_digit, 1, 1);
|
next_target.S = decfloat_to_int(&read_digit, 1, 1);
|
||||||
serwrite_uint16(next_target.S);
|
if (DEBUG)
|
||||||
|
serwrite_uint16(next_target.S);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
// if this is dwell, multiply by 1000 to convert seconds to milliseconds
|
// if this is dwell, multiply by 1000 to convert seconds to milliseconds
|
||||||
|
|
@ -151,9 +178,11 @@ void scan_char(uint8_t c) {
|
||||||
next_target.P = decfloat_to_int(&read_digit, 1000, 1);
|
next_target.P = decfloat_to_int(&read_digit, 1000, 1);
|
||||||
else
|
else
|
||||||
next_target.P = decfloat_to_int(&read_digit, 1, 1);
|
next_target.P = decfloat_to_int(&read_digit, 1, 1);
|
||||||
serwrite_uint16(next_target.P);
|
if (DEBUG)
|
||||||
|
serwrite_uint16(next_target.P);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// reset for next field
|
||||||
last_field = 0;
|
last_field = 0;
|
||||||
read_digit.sign = 0;
|
read_digit.sign = 0;
|
||||||
read_digit.mantissa = 0;
|
read_digit.mantissa = 0;
|
||||||
|
|
@ -161,11 +190,13 @@ void scan_char(uint8_t c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not in a comment?
|
// skip comments
|
||||||
if ((option_bitfield & OPTION_COMMENT) == 0) {
|
if ((option_bitfield & OPTION_COMMENT) == 0) {
|
||||||
|
// new field?
|
||||||
if (indexof(c, alphabet) >= 0) {
|
if (indexof(c, alphabet) >= 0) {
|
||||||
last_field = c;
|
last_field = c;
|
||||||
serial_writechar(c);
|
if (DEBUG)
|
||||||
|
serial_writechar(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process character
|
// process character
|
||||||
|
|
@ -223,6 +254,7 @@ void scan_char(uint8_t c) {
|
||||||
default:
|
default:
|
||||||
// can't do ranges in switch..case, so process actual digits here
|
// can't do ranges in switch..case, so process actual digits here
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
|
// this is simply mantissa = (mantissa * 10) + atoi(c) in different clothes
|
||||||
read_digit.mantissa = (read_digit.mantissa << 3) + (read_digit.mantissa << 1) + (c - '0');
|
read_digit.mantissa = (read_digit.mantissa << 3) + (read_digit.mantissa << 1) + (c - '0');
|
||||||
if (read_digit.exponent)
|
if (read_digit.exponent)
|
||||||
read_digit.exponent++;
|
read_digit.exponent++;
|
||||||
|
|
@ -230,14 +262,13 @@ void scan_char(uint8_t c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// got a command
|
// end of line
|
||||||
if (c == 10) {
|
if (c == 10) {
|
||||||
serial_writechar(c);
|
serial_writechar(c);
|
||||||
// process
|
// process
|
||||||
process_gcode_command(&next_target);
|
process_gcode_command(&next_target);
|
||||||
|
|
||||||
// save options
|
// reset 'seen comment'
|
||||||
// option_bitfield = next_target.option;
|
|
||||||
option_bitfield &= ~OPTION_COMMENT;
|
option_bitfield &= ~OPTION_COMMENT;
|
||||||
|
|
||||||
// reset variables
|
// reset variables
|
||||||
|
|
@ -252,7 +283,6 @@ void scan_char(uint8_t c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_gcode_command(GCODE_COMMAND *gcmd) {
|
void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
|
|
||||||
// convert relative to absolute
|
// convert relative to absolute
|
||||||
if (gcmd->option_relative) {
|
if (gcmd->option_relative) {
|
||||||
gcmd->target.X += startpoint.X;
|
gcmd->target.X += startpoint.X;
|
||||||
|
|
@ -261,7 +291,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
gcmd->target.E += startpoint.E;
|
gcmd->target.E += startpoint.E;
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicitly make unseen values equal to startpoint, otherwise relative position mode is a clusterfuck and who knows what other bugs could occur?
|
// explicitly make unseen values equal to startpoint, otherwise relative position mode is a clusterfuck
|
||||||
if (gcmd->seen_X == 0)
|
if (gcmd->seen_X == 0)
|
||||||
gcmd->target.X = startpoint.X;
|
gcmd->target.X = startpoint.X;
|
||||||
if (gcmd->seen_Y == 0)
|
if (gcmd->seen_Y == 0)
|
||||||
|
|
@ -288,14 +318,20 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// G2 - Arc Clockwise
|
// G2 - Arc Clockwise
|
||||||
|
// unimplemented
|
||||||
|
|
||||||
// G3 - Arc Counter-clockwise
|
// G3 - Arc Counter-clockwise
|
||||||
|
// unimplemented
|
||||||
|
|
||||||
// G4 - Dwell
|
// G4 - Dwell
|
||||||
case 4:
|
case 4:
|
||||||
xoff();
|
#ifdef XONXOFF
|
||||||
|
xoff();
|
||||||
|
#endif
|
||||||
delay_ms(gcmd->P);
|
delay_ms(gcmd->P);
|
||||||
xon();
|
#ifdef XONXOFF
|
||||||
|
xon();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// G20 - inches as units
|
// G20 - inches as units
|
||||||
|
|
@ -312,6 +348,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
case 30:
|
case 30:
|
||||||
enqueue(&gcmd->target);
|
enqueue(&gcmd->target);
|
||||||
// no break here, G30 is move and then go home
|
// no break here, G30 is move and then go home
|
||||||
|
|
||||||
// G28 - go home
|
// G28 - go home
|
||||||
case 28:
|
case 28:
|
||||||
/*
|
/*
|
||||||
|
|
@ -321,6 +358,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
SpecialMoveXY(-250L * STEPS_PER_MM_X, -250L * STEPS_PER_MM_Y, FEEDRATE_FAST_XY);
|
SpecialMoveXY(-250L * STEPS_PER_MM_X, -250L * STEPS_PER_MM_Y, FEEDRATE_FAST_XY);
|
||||||
startpoint.X = startpoint.Y = 0;
|
startpoint.X = startpoint.Y = 0;
|
||||||
|
|
||||||
|
// move forward a bit
|
||||||
SpecialMoveXY(5 * STEPS_PER_MM_X, 5 * STEPS_PER_MM_Y, FEEDRATE_SLOW_XY);
|
SpecialMoveXY(5 * STEPS_PER_MM_X, 5 * STEPS_PER_MM_Y, FEEDRATE_SLOW_XY);
|
||||||
|
|
||||||
// move back in to endstops slowly
|
// move back in to endstops slowly
|
||||||
|
|
@ -339,7 +377,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
SpecialMoveZ(-250L * STEPS_PER_MM_Z, FEEDRATE_FAST_Z);
|
SpecialMoveZ(-250L * STEPS_PER_MM_Z, FEEDRATE_FAST_Z);
|
||||||
startpoint.Z = 0;
|
startpoint.Z = 0;
|
||||||
|
|
||||||
// move out a bit
|
// move forward a bit
|
||||||
SpecialMoveZ(5 * STEPS_PER_MM_Z, FEEDRATE_SLOW_Z);
|
SpecialMoveZ(5 * STEPS_PER_MM_Z, FEEDRATE_SLOW_Z);
|
||||||
|
|
||||||
// move back into endstop slowly
|
// move back into endstop slowly
|
||||||
|
|
@ -354,7 +392,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
/*
|
/*
|
||||||
Home E
|
Home E
|
||||||
*/
|
*/
|
||||||
// extruder only runs one way anyway
|
// extruder only runs one way and we have no "endstop", just set this point as home
|
||||||
startpoint.E = current_position.E = 0;
|
startpoint.E = current_position.E = 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
@ -374,7 +412,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
startpoint.X = startpoint.Y = startpoint.Z = startpoint.E = 0;
|
startpoint.X = startpoint.Y = startpoint.Z = startpoint.E = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TODO: spit an error
|
// unknown gcode: spit an error
|
||||||
default:
|
default:
|
||||||
serial_writestr_P(PSTR("E: Bad G-code "));
|
serial_writestr_P(PSTR("E: Bad G-code "));
|
||||||
serwrite_uint8(gcmd->G);
|
serwrite_uint8(gcmd->G);
|
||||||
|
|
@ -435,14 +473,29 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
|
||||||
case 106:
|
case 106:
|
||||||
WRITE(FAN_PIN, 1);
|
WRITE(FAN_PIN, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// M107- fan off
|
// M107- fan off
|
||||||
case 107:
|
case 107:
|
||||||
WRITE(FAN_PIN, 0);
|
WRITE(FAN_PIN, 0);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO: spit an error
|
// M130- heater P factor
|
||||||
|
case 130:
|
||||||
|
if (gcmd->seen_S)
|
||||||
|
p_factor = gcmd->S;
|
||||||
|
break;
|
||||||
|
// M131- heater I factor
|
||||||
|
case 131:
|
||||||
|
if (gcmd->seen_S)
|
||||||
|
i_factor = gcmd->S;
|
||||||
|
break;
|
||||||
|
// M132- heater D factor
|
||||||
|
case 132:
|
||||||
|
if (gcmd->seen_S)
|
||||||
|
d_factor = gcmd->S;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// unknown mcode: spit an error
|
||||||
default:
|
default:
|
||||||
serial_writestr_P(PSTR("E: Bad M-code "));
|
serial_writestr_P(PSTR("E: Bad M-code "));
|
||||||
serwrite_uint8(gcmd->M);
|
serwrite_uint8(gcmd->M);
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,14 @@
|
||||||
|
|
||||||
#include "dda.h"
|
#include "dda.h"
|
||||||
|
|
||||||
|
// this is a very crude decimal-based floating point structure. a real floating point would at least have signed exponent
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t sign :1;
|
uint32_t sign :1;
|
||||||
uint32_t mantissa :24;
|
uint32_t mantissa :24;
|
||||||
uint32_t exponent :7;
|
uint32_t exponent :7;
|
||||||
} decfloat;
|
} decfloat;
|
||||||
|
|
||||||
|
// this holds all the possible data from a received command
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t seen_G :1;
|
uint8_t seen_G :1;
|
||||||
uint8_t seen_M :1;
|
uint8_t seen_M :1;
|
||||||
|
|
@ -30,16 +32,26 @@ typedef struct {
|
||||||
uint8_t M;
|
uint8_t M;
|
||||||
TARGET target;
|
TARGET target;
|
||||||
|
|
||||||
uint16_t S;
|
int16_t S;
|
||||||
uint16_t P;
|
uint16_t P;
|
||||||
} GCODE_COMMAND;
|
} GCODE_COMMAND;
|
||||||
|
|
||||||
|
// the command being processed
|
||||||
extern GCODE_COMMAND next_target;
|
extern GCODE_COMMAND next_target;
|
||||||
|
|
||||||
|
// utility functions
|
||||||
int8_t indexof(uint8_t c, const char *string);
|
int8_t indexof(uint8_t c, const char *string);
|
||||||
int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator);
|
int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator);
|
||||||
|
|
||||||
|
// this is where we construct a move without a gcode command, useful for gcodes which require multiple moves eg; homing
|
||||||
|
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f);
|
||||||
|
void SpecialMoveZ(int32_t z, uint32_t f);
|
||||||
|
void SpecialMoveE(int32_t e, uint32_t f);
|
||||||
|
|
||||||
|
// accept the next character and process it
|
||||||
void scan_char(uint8_t c);
|
void scan_char(uint8_t c);
|
||||||
|
|
||||||
|
// when we have a whole line, feed it to this
|
||||||
void process_gcode_command(GCODE_COMMAND *gcmd);
|
void process_gcode_command(GCODE_COMMAND *gcmd);
|
||||||
|
|
||||||
#endif /* _GCODE_H */
|
#endif /* _GCODE_H */
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
move buffer size, in number of moves
|
move buffer size, in number of moves
|
||||||
note that each move takes a fair chunk of ram (71 bytes as of this writing) so don't make the buffer too big - a bigger serial readbuffer may help more than increasing this unless your gcodes are more than 70 characters long on average.
|
note that each move takes a fair chunk of ram (69 bytes as of this writing) so don't make the buffer too big - a bigger serial readbuffer may help more than increasing this unless your gcodes are more than 70 characters long on average.
|
||||||
however, a larger movebuffer will probably help with lots of short moves, as each move takes a bunch of math to set up
|
however, a larger movebuffer will probably help with lots of short consecutive moves, as each move takes a bunch of math (hence time) to set up
|
||||||
*/
|
*/
|
||||||
#define MOVEBUFFER_SIZE 8
|
#define MOVEBUFFER_SIZE 8
|
||||||
|
|
||||||
|
|
@ -12,9 +12,11 @@
|
||||||
axis calculations, adjust as necessary
|
axis calculations, adjust as necessary
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// XY can have lots of precision and still move speedily, so microstepping is helpful
|
||||||
#define X_STEPS_PER_REV 3200.0
|
#define X_STEPS_PER_REV 3200.0
|
||||||
#define Y_STEPS_PER_REV X_STEPS_PER_REV
|
#define Y_STEPS_PER_REV X_STEPS_PER_REV
|
||||||
// we need more speed than precision on Z, turn off microstepping
|
|
||||||
|
// we need far more speed than precision on Z due to the threaded rod drive, turn off microstepping
|
||||||
#define Z_STEPS_PER_REV 200.0
|
#define Z_STEPS_PER_REV 200.0
|
||||||
|
|
||||||
#define X_COG_CIRCUMFERENCE (4.77 * 16.0)
|
#define X_COG_CIRCUMFERENCE (4.77 * 16.0)
|
||||||
|
|
@ -22,6 +24,8 @@
|
||||||
// also try:
|
// also try:
|
||||||
// #define XY_COG_RADIUS 9.5
|
// #define XY_COG_RADIUS 9.5
|
||||||
// #define XY_COG_CIRCUMFERENCE (XY_COG_RADIUS * PI * 2)
|
// #define XY_COG_CIRCUMFERENCE (XY_COG_RADIUS * PI * 2)
|
||||||
|
|
||||||
|
// this is the ratio between number of teeth on the Z motor gear, and teeth on the Z leadscrew base gear.
|
||||||
#define Z_GEAR_RATIO 1.0
|
#define Z_GEAR_RATIO 1.0
|
||||||
|
|
||||||
// we need more torque and smoothness at very low speeds on E, maximum microstepping
|
// we need more torque and smoothness at very low speeds on E, maximum microstepping
|
||||||
|
|
@ -30,6 +34,26 @@
|
||||||
#define EXTRUDER_INLET_DIAMETER 3.0
|
#define EXTRUDER_INLET_DIAMETER 3.0
|
||||||
#define EXTRUDER_NOZZLE_DIAMETER 0.8
|
#define EXTRUDER_NOZZLE_DIAMETER 0.8
|
||||||
|
|
||||||
|
// these feedrates are used during homing and G0 rapid moves
|
||||||
|
#define FEEDRATE_FAST_XY 6000
|
||||||
|
#define FEEDRATE_SLOW_XY 300
|
||||||
|
|
||||||
|
#define FEEDRATE_FAST_Z 6000
|
||||||
|
#define FEEDRATE_SLOW_Z 300
|
||||||
|
|
||||||
|
#define FEEDRATE_FAST_E 1200
|
||||||
|
|
||||||
|
// this is how many steps to suck back the filament by when we stop
|
||||||
|
#define E_STARTSTOP_STEPS 20
|
||||||
|
|
||||||
|
// extruder settings
|
||||||
|
#define TEMP_HYSTERESIS 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
calculated values - you shouldn't need to touch these
|
||||||
|
however feel free to put in your own values if they can be more precise than the calculated approximations, remembering that they must end up being integers- floating point by preprocessor only thanks!
|
||||||
|
*/
|
||||||
|
|
||||||
#define STEPS_PER_MM_X ((uint32_t) ((X_STEPS_PER_REV / X_COG_CIRCUMFERENCE) + 0.5))
|
#define STEPS_PER_MM_X ((uint32_t) ((X_STEPS_PER_REV / X_COG_CIRCUMFERENCE) + 0.5))
|
||||||
#define STEPS_PER_MM_Y ((uint32_t) ((Y_STEPS_PER_REV / Y_COG_CIRCUMFERENCE) + 0.5))
|
#define STEPS_PER_MM_Y ((uint32_t) ((Y_STEPS_PER_REV / Y_COG_CIRCUMFERENCE) + 0.5))
|
||||||
#define STEPS_PER_MM_Z ((uint32_t) ((Z_STEPS_PER_REV * Z_GEAR_RATIO) + 0.5))
|
#define STEPS_PER_MM_Z ((uint32_t) ((Z_STEPS_PER_REV * Z_GEAR_RATIO) + 0.5))
|
||||||
|
|
@ -39,33 +63,19 @@
|
||||||
// does this refer to filament or extrudate? extrudate depends on XY distance vs E distance.. hm lets go with filament
|
// does this refer to filament or extrudate? extrudate depends on XY distance vs E distance.. hm lets go with filament
|
||||||
#define STEPS_PER_MM_E ((uint32_t) ((E_STEPS_PER_REV / (EXTRUDER_SHAFT_RADIUS * PI * EXTRUDER_INLET_DIAMETER)) + 0.5))
|
#define STEPS_PER_MM_E ((uint32_t) ((E_STEPS_PER_REV / (EXTRUDER_SHAFT_RADIUS * PI * EXTRUDER_INLET_DIAMETER)) + 0.5))
|
||||||
|
|
||||||
#define FEEDRATE_FAST_XY 6000
|
// same as above with 25.4 scale factor
|
||||||
#define FEEDRATE_SLOW_XY 300
|
#define STEPS_PER_IN_X ((uint32_t) ((25.4 * X_STEPS_PER_REV / X_COG_CIRCUMFERENCE) + 0.5))
|
||||||
#define FEEDRATE_FAST_Z 6000
|
#define STEPS_PER_IN_Y ((uint32_t) ((25.4 * Y_STEPS_PER_REV / Y_COG_CIRCUMFERENCE) + 0.5))
|
||||||
#define FEEDRATE_SLOW_Z 300
|
#define STEPS_PER_IN_Z ((uint32_t) ((25.4 * Z_STEPS_PER_REV * Z_GEAR_RATIO) + 0.5))
|
||||||
|
#define STEPS_PER_IN_E ((uint32_t) ((25.4 * E_STEPS_PER_REV / (EXTRUDER_SHAFT_RADIUS * PI * EXTRUDER_INLET_DIAMETER)) + 0.5))
|
||||||
#define E_STARTSTOP_STEPS 20
|
|
||||||
#define FEEDRATE_FAST_E 1200
|
|
||||||
|
|
||||||
/*
|
|
||||||
extruder settings
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TEMP_HYSTERESIS 2
|
|
||||||
|
|
||||||
/*
|
|
||||||
calculated values - you shouldn't need to touch these
|
|
||||||
however feel free to put in your own values if they can be more precise than the calculated approximations, remembering that they must end up being integers- floating point by preprocessor only thanks!
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
// inverse, used in distance calculation during DDA setup
|
||||||
#define UM_PER_STEP_X ((uint32_t) ((1000.0 / STEPS_PER_MM_X) + 0.5))
|
#define UM_PER_STEP_X ((uint32_t) ((1000.0 / STEPS_PER_MM_X) + 0.5))
|
||||||
#define UM_PER_STEP_Y ((uint32_t) ((1000.0 / STEPS_PER_MM_Y) + 0.5))
|
#define UM_PER_STEP_Y ((uint32_t) ((1000.0 / STEPS_PER_MM_Y) + 0.5))
|
||||||
#define UM_PER_STEP_Z ((uint32_t) ((1000.0 / STEPS_PER_MM_Z) + 0.5))
|
#define UM_PER_STEP_Z ((uint32_t) ((1000.0 / STEPS_PER_MM_Z) + 0.5))
|
||||||
#define UM_PER_STEP_E ((uint32_t) ((1000.0 / STEPS_PER_MM_E) + 0.5))
|
#define UM_PER_STEP_E ((uint32_t) ((1000.0 / STEPS_PER_MM_E) + 0.5))
|
||||||
|
|
||||||
/*
|
// should be the same for all machines! ;)
|
||||||
should be the same for all machines! ;)
|
|
||||||
*/
|
|
||||||
#define PI 3.1415926535
|
#define PI 3.1415926535
|
||||||
|
|
||||||
#endif /* _MACHINE_H */
|
#endif /* _MACHINE_H */
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,6 @@ inline void init(void) {
|
||||||
clock_setup();
|
clock_setup();
|
||||||
|
|
||||||
// set up variables
|
// set up variables
|
||||||
|
|
||||||
// slow default
|
|
||||||
current_position.F = FEEDRATE_SLOW_Z;
|
current_position.F = FEEDRATE_SLOW_Z;
|
||||||
memcpy(&startpoint, ¤t_position, sizeof(TARGET));
|
memcpy(&startpoint, ¤t_position, sizeof(TARGET));
|
||||||
memcpy(&(next_target.target), ¤t_position, sizeof(TARGET));
|
memcpy(&(next_target.target), ¤t_position, sizeof(TARGET));
|
||||||
|
|
@ -83,14 +81,10 @@ inline void init(void) {
|
||||||
|
|
||||||
// say hi to host
|
// say hi to host
|
||||||
serial_writestr_P(PSTR("Start\n"));
|
serial_writestr_P(PSTR("Start\n"));
|
||||||
|
|
||||||
// start queue
|
|
||||||
//enableTimerInterrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clock_250ms(void);
|
||||||
void clock_250ms() {
|
void clock_250ms() {
|
||||||
static uint8_t report = 0;
|
|
||||||
|
|
||||||
temp_tick();
|
temp_tick();
|
||||||
|
|
||||||
if (steptimeout > (30 * 4))
|
if (steptimeout > (30 * 4))
|
||||||
|
|
@ -98,18 +92,13 @@ void clock_250ms() {
|
||||||
else
|
else
|
||||||
steptimeout++;
|
steptimeout++;
|
||||||
|
|
||||||
report++;
|
ifclock (CLOCK_FLAG_1S) {
|
||||||
if (report == 4) {
|
|
||||||
report = 0;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// current move
|
// current move
|
||||||
serial_writestr_P(PSTR("DDA: f#"));
|
serial_writestr_P(PSTR("DDA: f#"));
|
||||||
serwrite_int32(movebuffer[mb_head].f_counter);
|
serwrite_int32(movebuffer[mb_tail].f_counter);
|
||||||
serial_writechar('/');
|
serial_writechar('/');
|
||||||
// serwrite_uint16(movebuffer[mb_head].f_scale);
|
serwrite_int16(movebuffer[mb_tail].f_delta);
|
||||||
// serial_writechar('/');
|
|
||||||
serwrite_int16(movebuffer[mb_head].f_delta);
|
|
||||||
serial_writechar('\n');
|
serial_writechar('\n');
|
||||||
|
|
||||||
// current position
|
// current position
|
||||||
|
|
@ -155,7 +144,7 @@ int main (void)
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// if queue is full, no point in reading chars- host will just have to wait
|
// if queue is full, no point in reading chars- host will just have to wait
|
||||||
if (serial_rxchars() && !queue_full()) {
|
if ((serial_rxchars() != 0) && (queue_full() == 0)) {
|
||||||
uint8_t c = serial_popchar();
|
uint8_t c = serial_popchar();
|
||||||
scan_char(c);
|
scan_char(c);
|
||||||
}
|
}
|
||||||
|
|
@ -163,66 +152,5 @@ int main (void)
|
||||||
ifclock(CLOCK_FLAG_250MS) {
|
ifclock(CLOCK_FLAG_250MS) {
|
||||||
clock_250ms();
|
clock_250ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ifclock(CLOCK_FLAG_250MS_TEMPCHECK) {
|
|
||||||
// temp_tick();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ifclock(CLOCK_FLAG_250MS_STEPTIMEOUT) {
|
|
||||||
// if (steptimeout > (30 * 4))
|
|
||||||
// disable_steppers();
|
|
||||||
// else
|
|
||||||
// steptimeout++;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ifclock(CLOCK_FLAG_250MS_REPORT) {
|
|
||||||
// report++;
|
|
||||||
// if (report == 4) {
|
|
||||||
// report = 0;
|
|
||||||
//
|
|
||||||
// if (DEBUG) {
|
|
||||||
// // current move
|
|
||||||
// serial_writestr_P(PSTR("DDA: f#"));
|
|
||||||
// serwrite_int32(movebuffer[mb_head].f_counter);
|
|
||||||
// serial_writechar('/');
|
|
||||||
// // serwrite_uint16(movebuffer[mb_head].f_scale);
|
|
||||||
// // serial_writechar('/');
|
|
||||||
// serwrite_int16(movebuffer[mb_head].f_delta);
|
|
||||||
// serial_writechar('\n');
|
|
||||||
//
|
|
||||||
// // current position
|
|
||||||
// serial_writestr_P(PSTR("Pos: "));
|
|
||||||
// serwrite_int32(current_position.X);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(current_position.Y);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(current_position.Z);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(current_position.E);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_uint32(current_position.F);
|
|
||||||
// serial_writechar('\n');
|
|
||||||
//
|
|
||||||
// // target position
|
|
||||||
// serial_writestr_P(PSTR("Dst: "));
|
|
||||||
// serwrite_int32(movebuffer[mb_tail].endpoint.X);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(movebuffer[mb_tail].endpoint.Y);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(movebuffer[mb_tail].endpoint.Z);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_int32(movebuffer[mb_tail].endpoint.E);
|
|
||||||
// serial_writechar(',');
|
|
||||||
// serwrite_uint32(movebuffer[mb_tail].endpoint.F);
|
|
||||||
// serial_writechar('\n');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Queue
|
|
||||||
// print_queue();
|
|
||||||
//
|
|
||||||
// // temperature
|
|
||||||
// temp_print();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
#define STEPPER_ENABLE_PIN DIO9
|
#define STEPPER_ENABLE_PIN DIO9
|
||||||
|
|
||||||
// list of PWM-able pins and corresponding timers
|
// list of PWM-able pins and corresponding timers
|
||||||
// timer1 is reserved for step timing
|
// timer1 is used for step timing so don't use OC1A/OC1B (DIO9/DIO10)
|
||||||
// OC0A DIO6
|
// OC0A DIO6
|
||||||
// OC0B DIO5
|
// OC0B DIO5
|
||||||
// OC1A DIO9
|
// OC1A DIO9
|
||||||
|
|
@ -132,7 +132,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef STEPPER_ENABLE_PIN
|
#ifdef STEPPER_ENABLE_PIN
|
||||||
// for connection to stepper driver ENABLE pins
|
// for connection to stepper driver ENABLE pins (negative asserted)
|
||||||
// #define enable_steppers() WRITE(STEPPER_ENABLE_PIN, 0)
|
// #define enable_steppers() WRITE(STEPPER_ENABLE_PIN, 0)
|
||||||
// #define disable_steppers() WRITE(STEPPER_ENABLE_PIN, 1)
|
// #define disable_steppers() WRITE(STEPPER_ENABLE_PIN, 1)
|
||||||
// for connection to ATX PSU PWR_ON signal
|
// for connection to ATX PSU PWR_ON signal
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ void ringbuffer_writechar(ringbuffer *buf, uint8_t data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index)
|
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index)
|
||||||
{
|
{
|
||||||
return buf->data[_rb_mod(buf->read_pointer + index, buf->size)];
|
return buf->data[_rb_mod(buf->read_pointer + index, buf->size)];
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
// ringbuffer head/tail/length precision. change to uint16_t if you want a buffer bigger than 252 bytes or so
|
||||||
#define RB_BITS uint8_t
|
#define RB_BITS uint8_t
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -13,15 +14,19 @@ typedef struct {
|
||||||
volatile RB_BITS data[];
|
volatile RB_BITS data[];
|
||||||
} ringbuffer;
|
} ringbuffer;
|
||||||
|
|
||||||
|
// initialize a ringbuffer
|
||||||
void ringbuffer_init(ringbuffer *buf, RB_BITS bufsize);
|
void ringbuffer_init(ringbuffer *buf, RB_BITS bufsize);
|
||||||
|
|
||||||
|
// return how many bytes can be read or written
|
||||||
RB_BITS ringbuffer_canread(ringbuffer *buf);
|
RB_BITS ringbuffer_canread(ringbuffer *buf);
|
||||||
RB_BITS ringbuffer_canwrite(ringbuffer *buf);
|
RB_BITS ringbuffer_canwrite(ringbuffer *buf);
|
||||||
|
|
||||||
|
// read bytes
|
||||||
uint8_t ringbuffer_readchar(ringbuffer *buf);
|
uint8_t ringbuffer_readchar(ringbuffer *buf);
|
||||||
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index);
|
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index);
|
||||||
RB_BITS ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, RB_BITS size);
|
RB_BITS ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, RB_BITS size);
|
||||||
|
|
||||||
|
// write bytes
|
||||||
void ringbuffer_writechar(ringbuffer *buf, uint8_t data);
|
void ringbuffer_writechar(ringbuffer *buf, uint8_t data);
|
||||||
RB_BITS ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, RB_BITS size);
|
RB_BITS ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, RB_BITS size);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,15 +121,17 @@ void serial_writestr_P(PGM_P data)
|
||||||
serial_writechar(r);
|
serial_writechar(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void xoff() {
|
#ifdef XONXOFF
|
||||||
flowflags = FLOWFLAG_SEND_XOFF;
|
void xon() {
|
||||||
// enable TX interrupt so we can send this character
|
if (flowflags & FLOWFLAG_SENT_XOFF)
|
||||||
UCSR0B |= (1 << UDRIE0);
|
flowflags = FLOWFLAG_SEND_XON;
|
||||||
}
|
// enable TX interrupt so we can send this character
|
||||||
|
UCSR0B |= (1 << UDRIE0);
|
||||||
|
}
|
||||||
|
|
||||||
void xon() {
|
void xoff() {
|
||||||
if (flowflags & FLOWFLAG_SENT_XOFF)
|
flowflags = FLOWFLAG_SEND_XOFF;
|
||||||
flowflags = FLOWFLAG_SEND_XON;
|
// enable TX interrupt so we can send this character
|
||||||
// enable TX interrupt so we can send this character
|
UCSR0B |= (1 << UDRIE0);
|
||||||
UCSR0B |= (1 << UDRIE0);
|
}
|
||||||
}
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,31 @@
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
// initialise serial subsystem
|
||||||
void serial_init(void);
|
void serial_init(void);
|
||||||
|
|
||||||
|
// return number of characters in the receive and send buffer
|
||||||
uint16_t serial_rxchars(void);
|
uint16_t serial_rxchars(void);
|
||||||
uint16_t serial_txchars(void);
|
uint16_t serial_txchars(void);
|
||||||
|
|
||||||
|
// read one character
|
||||||
uint8_t serial_popchar(void);
|
uint8_t serial_popchar(void);
|
||||||
|
// send one character
|
||||||
void serial_writechar(uint8_t data);
|
void serial_writechar(uint8_t data);
|
||||||
|
|
||||||
|
// read/write many characters
|
||||||
uint16_t serial_recvblock(uint8_t *block, int blocksize);
|
uint16_t serial_recvblock(uint8_t *block, int blocksize);
|
||||||
void serial_writeblock(void *data, int datalen);
|
void serial_writeblock(void *data, int datalen);
|
||||||
|
|
||||||
|
// write from flash
|
||||||
void serial_writechar_P(PGM_P data);
|
void serial_writechar_P(PGM_P data);
|
||||||
void serial_writeblock_P(PGM_P data, int datalen);
|
void serial_writeblock_P(PGM_P data, int datalen);
|
||||||
|
|
||||||
void serial_writestr_P(PGM_P data);
|
void serial_writestr_P(PGM_P data);
|
||||||
|
|
||||||
void xoff(void);
|
#ifdef XONXOFF
|
||||||
void xon(void);
|
// XON/XOFF flow control
|
||||||
|
void xoff(void);
|
||||||
|
void xon(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _SERIAL_H */
|
#endif /* _SERIAL_H */
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,13 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// functions for sending hexadecimal
|
||||||
void serwrite_hex4(uint8_t v);
|
void serwrite_hex4(uint8_t v);
|
||||||
void serwrite_hex8(uint8_t v);
|
void serwrite_hex8(uint8_t v);
|
||||||
void serwrite_hex16(uint16_t v);
|
void serwrite_hex16(uint16_t v);
|
||||||
void serwrite_hex32(uint32_t v);
|
void serwrite_hex32(uint32_t v);
|
||||||
|
|
||||||
|
// functions for sending decimal
|
||||||
#define serwrite_uint8(v) serwrite_uint32(v)
|
#define serwrite_uint8(v) serwrite_uint32(v)
|
||||||
#define serwrite_int8(v) serwrite_int32(v)
|
#define serwrite_int8(v) serwrite_int32(v)
|
||||||
#define serwrite_uint16(v) serwrite_uint32(v)
|
#define serwrite_uint16(v) serwrite_uint32(v)
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,6 @@ uint8_t temp_flags = 0;
|
||||||
#define TEMP_FLAG_PRESENT 1
|
#define TEMP_FLAG_PRESENT 1
|
||||||
#define TEMP_FLAG_TCOPEN 2
|
#define TEMP_FLAG_TCOPEN 2
|
||||||
|
|
||||||
#define PID_SCALE 1024L
|
|
||||||
|
|
||||||
uint16_t temp_read() {
|
uint16_t temp_read() {
|
||||||
uint16_t temp;
|
uint16_t temp;
|
||||||
SPCR = MASK(MSTR) | MASK(SPE);
|
SPCR = MASK(MSTR) | MASK(SPE);
|
||||||
|
|
@ -55,6 +53,10 @@ uint16_t temp_read() {
|
||||||
for (;(SPSR & MASK(SPIF)) == 0;);
|
for (;(SPSR & MASK(SPIF)) == 0;);
|
||||||
temp |= SPDR;
|
temp |= SPDR;
|
||||||
|
|
||||||
|
WRITE(SS, 0);
|
||||||
|
|
||||||
|
SPCR = 0;
|
||||||
|
|
||||||
temp_flags = 0;
|
temp_flags = 0;
|
||||||
if ((temp & 0x8002) == 0) {
|
if ((temp & 0x8002) == 0) {
|
||||||
// got "device id"
|
// got "device id"
|
||||||
|
|
@ -69,10 +71,6 @@ uint16_t temp_read() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE(SS, 0);
|
|
||||||
|
|
||||||
SPCR = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,15 +108,26 @@ void temp_tick() {
|
||||||
uint16_t last_temp = current_temp;
|
uint16_t last_temp = current_temp;
|
||||||
temp_read();
|
temp_read();
|
||||||
|
|
||||||
int16_t t_delta = target_temp - current_temp;
|
int16_t t_error = target_temp - current_temp;
|
||||||
|
|
||||||
// PID stuff
|
// PID stuff
|
||||||
heater_p = t_delta;
|
// proportional
|
||||||
heater_i += t_delta;
|
heater_p = t_error;
|
||||||
// note: D follows temp rather than error so there's no large derivative when the target temperature changes
|
|
||||||
|
// integral
|
||||||
|
heater_i += t_error;
|
||||||
|
// prevent integrator wind-up
|
||||||
|
if (heater_i > I_LIMIT)
|
||||||
|
heater_i = I_LIMIT;
|
||||||
|
else if (heater_i < -I_LIMIT)
|
||||||
|
heater_i = -I_LIMIT;
|
||||||
|
|
||||||
|
// derivative
|
||||||
|
// note: D follows temp rather than error so there's no large derivative when the target changes
|
||||||
heater_d = (current_temp - last_temp);
|
heater_d = (current_temp - last_temp);
|
||||||
|
|
||||||
uint8_t pid_output = (
|
// combine factors
|
||||||
|
int32_t pid_output_intermed = (
|
||||||
(
|
(
|
||||||
(((int32_t) heater_p) * p_factor) +
|
(((int32_t) heater_p) * p_factor) +
|
||||||
(((int32_t) heater_i) * i_factor) +
|
(((int32_t) heater_i) * i_factor) +
|
||||||
|
|
@ -126,6 +135,15 @@ void temp_tick() {
|
||||||
) / PID_SCALE
|
) / PID_SCALE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// rebase and limit factors
|
||||||
|
uint8_t pid_output;
|
||||||
|
if (pid_output_intermed > 127)
|
||||||
|
pid_output = 255;
|
||||||
|
else if (pid_output_intermed < -128)
|
||||||
|
pid_output = 0;
|
||||||
|
else
|
||||||
|
pid_output = (pid_output_intermed + 128);
|
||||||
|
|
||||||
#ifdef HEATER_PIN_PWMABLE
|
#ifdef HEATER_PIN_PWMABLE
|
||||||
HEATER_PIN_PWMABLE = pid_output
|
HEATER_PIN_PWMABLE = pid_output
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,31 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// extruder heater PID factors
|
||||||
|
// google "PID without a PHD" if you don't understand this PID stuff
|
||||||
|
extern int32_t p_factor;
|
||||||
|
extern int32_t i_factor;
|
||||||
|
extern int32_t d_factor;
|
||||||
|
|
||||||
|
#define PID_SCALE 1024L
|
||||||
|
#define I_LIMIT 4000
|
||||||
|
|
||||||
|
// read temperature from sensor
|
||||||
uint16_t temp_read(void);
|
uint16_t temp_read(void);
|
||||||
|
|
||||||
|
// set target temperature
|
||||||
void temp_set(uint16_t t);
|
void temp_set(uint16_t t);
|
||||||
|
|
||||||
|
// return last read temperature
|
||||||
uint16_t temp_get(void);
|
uint16_t temp_get(void);
|
||||||
|
|
||||||
|
// true if last read temp is close to target temp, false otherwise
|
||||||
uint8_t temp_achieved(void);
|
uint8_t temp_achieved(void);
|
||||||
|
|
||||||
|
// send current temperature to host
|
||||||
void temp_print(void);
|
void temp_print(void);
|
||||||
|
|
||||||
|
// periodically read temperature and update heater with PID
|
||||||
void temp_tick(void);
|
void temp_tick(void);
|
||||||
|
|
||||||
#endif /* _TIMER_H */
|
#endif /* _TIMER_H */
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include "dda.h"
|
#include "dda.h"
|
||||||
|
|
||||||
ISR(TIMER1_COMPA_vect) {
|
ISR(TIMER1_COMPA_vect) {
|
||||||
// WRITE(SCK, 0);
|
|
||||||
if (movebuffer[mb_tail].live) {
|
if (movebuffer[mb_tail].live) {
|
||||||
// this interrupt can be interruptible
|
// this interrupt can be interruptible
|
||||||
// TODO: remove when not debugging
|
// TODO: remove when not debugging
|
||||||
|
|
@ -19,19 +18,14 @@ ISR(TIMER1_COMPA_vect) {
|
||||||
// cli();
|
// cli();
|
||||||
// enableTimerInterrupt();
|
// enableTimerInterrupt();
|
||||||
}
|
}
|
||||||
// WRITE(SCK, 1);
|
|
||||||
|
|
||||||
// perhaps we can fall directly into dda_start instead of waiting for another step
|
// fall directly into dda_start instead of waiting for another step
|
||||||
if (movebuffer[mb_tail].live == 0) {
|
if (movebuffer[mb_tail].live == 0)
|
||||||
next_move();
|
next_move();
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupTimerInterrupt()
|
void setupTimerInterrupt()
|
||||||
{
|
{
|
||||||
//clear the registers
|
|
||||||
|
|
||||||
// no outputs
|
// no outputs
|
||||||
TCCR1A = 0;
|
TCCR1A = 0;
|
||||||
// CTC mode
|
// CTC mode
|
||||||
|
|
@ -43,6 +37,8 @@ void setupTimerInterrupt()
|
||||||
setTimer(10000);
|
setTimer(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the following are all from reprap project 5D firmware
|
||||||
|
|
||||||
uint8_t getTimerResolution(const uint32_t delay)
|
uint8_t getTimerResolution(const uint32_t delay)
|
||||||
{
|
{
|
||||||
// these also represent frequency: 1000000 / delay / 2 = frequency in hz.
|
// these also represent frequency: 1000000 / delay / 2 = frequency in hz.
|
||||||
|
|
@ -142,7 +138,6 @@ void delay_ms(uint32_t delay) {
|
||||||
delayMicrosecondsInterruptible(delay * 1000);
|
delayMicrosecondsInterruptible(delay * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// from reprap project 5D firmware
|
|
||||||
void delayMicrosecondsInterruptible(uint16_t us)
|
void delayMicrosecondsInterruptible(uint16_t us)
|
||||||
{
|
{
|
||||||
// for a one-microsecond delay, simply return. the overhead
|
// for a one-microsecond delay, simply return. the overhead
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@
|
||||||
#define US * (F_CPU / 1000000)
|
#define US * (F_CPU / 1000000)
|
||||||
#define MS * (F_CPU / 1000)
|
#define MS * (F_CPU / 1000)
|
||||||
|
|
||||||
#define DEFAULT_TICK (100 US)
|
// #define DEFAULT_TICK (100 US)
|
||||||
#define WAITING_DELAY (10 MS)
|
#define WAITING_DELAY (10 MS)
|
||||||
|
|
||||||
void setupTimerInterrupt(void);
|
void setupTimerInterrupt(void);
|
||||||
|
|
||||||
uint8_t getTimerResolution(const uint32_t delay);
|
uint8_t getTimerResolution(const uint32_t delay);
|
||||||
void setTimerResolution(uint8_t r);
|
void setTimerResolution(uint8_t r);
|
||||||
|
|
||||||
uint16_t getTimerCeiling(const uint32_t delay);
|
uint16_t getTimerCeiling(const uint32_t delay);
|
||||||
|
#define setTimerCeiling(c) OCR1A = c
|
||||||
|
|
||||||
void setTimer(uint32_t delay);
|
void setTimer(uint32_t delay);
|
||||||
|
|
||||||
|
|
@ -28,6 +31,4 @@ void delayMicrosecondsInterruptible(unsigned int us);
|
||||||
#define enableTimerInterrupt() do { TIMSK1 |= (1<<OCIE1A); } while (0)
|
#define enableTimerInterrupt() do { TIMSK1 |= (1<<OCIE1A); } while (0)
|
||||||
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
|
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
|
||||||
|
|
||||||
#define setTimerCeiling(c) OCR1A = c
|
|
||||||
|
|
||||||
#endif /* _TIMER_H */
|
#endif /* _TIMER_H */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue