tons of commenting and tidying, fixes to heater PID loop

This commit is contained in:
Michael Moon 2010-02-04 23:22:16 +11:00
parent 8cc6fa6937
commit 4c47901b66
21 changed files with 372 additions and 335 deletions

View File

@ -11,6 +11,12 @@
#define MASK(PIN) (1 << PIN)
#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 _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))
@ -33,6 +39,10 @@
/*
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

View File

@ -19,7 +19,8 @@ volatile uint32_t clock = 0;
// 1/4 second tick
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() {
// use system clock
@ -39,17 +40,19 @@ void clock_setup() {
}
ISR(TIMER2_COMPA_vect) {
// WRITE(SCK, 0);
// global clock
#ifdef GLOBAL_CLOCK
clock++;
#endif
// 1/4 second tick
if (++clock_counter_250ms == 250) {
clock_flag_250ms = 255;
clock_flag |= CLOCK_FLAG_250MS;
clock_counter_250ms = 0;
if (++clock_counter_1s == 4) {
clock_flag |= CLOCK_FLAG_1S;
clock_counter_1s = 0;
}
}
// WRITE(SCK, 1);
}
#ifdef GLOBAL_CLOCK

View File

@ -9,25 +9,24 @@ void clock_setup(void);
uint32_t clock_read(void);
#endif
extern volatile uint8_t clock_flag_250ms;
extern volatile uint8_t clock_flag;
#define CLOCK_FLAG_250MS 1
// #define CLOCK_FLAG_250MS_TEMPCHECK 1
// #define CLOCK_FLAG_250MS_REPORT 2
// #define CLOCK_FLAG_250MS_STEPTIMEOUT 4
#define CLOCK_FLAG_1S 2
/*
ifclock() {}
so we can do stuff like:
ifclock(CLOCK_FLAG_250MS_REPORT) {
ifclock(CLOCK_FLAG_250MS) {
report();
}
or:
ifclock(CLOCK_FLAG_250MS_STEPTIMEOUT)
ifclock(CLOCK_FLAG_1S)
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 */

View File

@ -174,25 +174,6 @@ void dda_create(DDA *dda, TARGET *target) {
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->total_steps >> 1);
@ -206,8 +187,6 @@ void dda_create(DDA *dda, TARGET *target) {
if (distance < 2)
distance = dda->e_delta * UM_PER_STEP_E;
// if (distance < 2)
// distance = dda->f_delta;
if (DEBUG) {
serwrite_uint32(distance); serial_writechar(',');
@ -241,12 +220,6 @@ void dda_create(DDA *dda, TARGET *target) {
void dda_start(DDA *dda) {
// 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) {
// just change speed?
current_position.F = dda->endpoint.F;
@ -310,123 +283,110 @@ void dda_step(DDA *dda) {
if (DEBUG)
serial_writechar('!');
// turn 'L' light OFF so it's obvious if we froze in this routine
// 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 &= ~(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(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(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.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.F, dda->endpoint.F, dda->f_direction) & F_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.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.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) {
step_option |= REAL_MOVE;
if (step_option & X_CAN_STEP) {
dda->x_counter -= dda->x_delta;
if (dda->x_counter < 0) {
step_option |= REAL_MOVE;
x_step();
if (dda->x_direction)
current_position.X++;
else
current_position.X--;
x_step();
if (dda->x_direction)
current_position.X++;
else
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;
}
}
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;
else {
current_position.F -= 1;
if (current_position.F < dda->endpoint.F)
current_position.F = dda->endpoint.F;
}
step_option |= F_REAL_STEP;
}
}
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 (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);
// 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(']');
}
if (step_option & REAL_MOVE)
// 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
// if not, too bad. or insert a (very!) small delay here, or fire up a spare timer or something
unstep();
// turn 'L' light back on again
// if (DEBUG)
// WRITE(SCK, 1);
}

View File

@ -10,6 +10,7 @@
types
*/
// target is simply a point in space/time
typedef struct {
int32_t X;
int32_t Y;
@ -18,8 +19,8 @@ typedef struct {
uint32_t F;
} TARGET;
// this is a digital differential analyser data struct, holding both the initial values and the counters as it progresses
typedef struct {
// TARGET currentpoint;
TARGET endpoint;
uint8_t x_direction :1;
@ -51,9 +52,13 @@ typedef struct {
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;
// startpoint holds the end position of the most recently created DDA, so we know where the next one starts
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;
/*

View File

@ -8,7 +8,6 @@ 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);
@ -21,6 +20,7 @@ uint8_t queue_empty() {
}
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())
delay(WAITING_DELAY);
@ -31,24 +31,24 @@ void enqueue(TARGET *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;
#ifdef XONXOFF
// if queue is full, stop transmition
if (queue_full())
xoff();
#endif
// fire up in case we're not running yet
enableTimerInterrupt();
}
void next_move() {
if (queue_empty()) {
// queue is empty
// disable_steppers();
// setTimer(DEFAULT_TICK);
disableTimerInterrupt();
}
else {
// next item
uint8_t t = mb_tail;
t++;
if (t == MOVEBUFFER_SIZE)
@ -56,8 +56,11 @@ void next_move() {
dda_start(&movebuffer[t]);
mb_tail = t;
}
// restart transmission
xon();
#ifdef XONXOFF
// restart transmission
xon();
#endif
}
void print_queue() {

View File

@ -7,6 +7,7 @@
variables
*/
// this is the ringbuffer that holds the current and pending moves.
extern uint8_t mb_head;
extern uint8_t mb_tail;
extern DDA movebuffer[MOVEBUFFER_SIZE];
@ -15,10 +16,17 @@ extern DDA movebuffer[MOVEBUFFER_SIZE];
methods
*/
// queue status methods
uint8_t queue_full(void);
uint8_t queue_empty(void);
// add a new target to the queue
void enqueue(TARGET *t);
// called from step timer when current move is complete
void next_move(void);
// print queue status
void print_queue(void);
#endif /* _DDA_QUEUE */

View File

@ -69,6 +69,10 @@ int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator)
return r;
}
/*
public functions
*/
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f) {
TARGET t = startpoint;
t.X = x;
@ -91,10 +95,6 @@ void SpecialMoveE(int32_t e, uint32_t f) {
enqueue(&t);
}
/*
public functions
*/
void scan_char(uint8_t c) {
static uint8_t last_field = 0;
@ -102,38 +102,61 @@ void scan_char(uint8_t c) {
if (c >= 'a' && c <= 'z')
c &= ~32;
// process field
// process previous field
if (last_field) {
// check if we're seeing a new field or end of line
if ((indexof(c, alphabet) >= 0) || (c == 10)) {
switch (last_field) {
case 'G':
next_target.G = read_digit.mantissa;
serwrite_uint8(next_target.G);
if (DEBUG)
serwrite_uint8(next_target.G);
break;
case 'M':
next_target.M = read_digit.mantissa;
serwrite_uint8(next_target.M);
if (DEBUG)
serwrite_uint8(next_target.M);
break;
case 'X':
next_target.target.X = decfloat_to_int(&read_digit, STEPS_PER_MM_X, 1);
serwrite_int32(next_target.target.X);
if (next_target.option_inches)
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;
case 'Y':
next_target.target.Y = decfloat_to_int(&read_digit, STEPS_PER_MM_Y, 1);
serwrite_int32(next_target.target.Y);
if (next_target.option_inches)
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;
case 'Z':
next_target.target.Z = decfloat_to_int(&read_digit, STEPS_PER_MM_Z, 1);
serwrite_int32(next_target.target.Z);
if (next_target.option_inches)
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;
case 'E':
next_target.target.E = decfloat_to_int(&read_digit, STEPS_PER_MM_E, 1);
serwrite_uint32(next_target.target.E);
if (next_target.option_inches)
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;
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
next_target.target.F = decfloat_to_int(&read_digit, 1, 1);
serwrite_uint32(next_target.target.F);
if (next_target.option_inches)
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;
case 'S':
// 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
if (next_target.M == 104)
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
next_target.S = decfloat_to_int(&read_digit, 1, 1);
serwrite_uint16(next_target.S);
if (DEBUG)
serwrite_uint16(next_target.S);
break;
case 'P':
// 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);
else
next_target.P = decfloat_to_int(&read_digit, 1, 1);
serwrite_uint16(next_target.P);
if (DEBUG)
serwrite_uint16(next_target.P);
break;
}
// reset for next field
last_field = 0;
read_digit.sign = 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) {
// new field?
if (indexof(c, alphabet) >= 0) {
last_field = c;
serial_writechar(c);
if (DEBUG)
serial_writechar(c);
}
// process character
@ -223,6 +254,7 @@ void scan_char(uint8_t c) {
default:
// can't do ranges in switch..case, so process actual digits here
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');
if (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) {
serial_writechar(c);
// process
process_gcode_command(&next_target);
// save options
// option_bitfield = next_target.option;
// reset 'seen comment'
option_bitfield &= ~OPTION_COMMENT;
// reset variables
@ -252,7 +283,6 @@ void scan_char(uint8_t c) {
}
void process_gcode_command(GCODE_COMMAND *gcmd) {
// convert relative to absolute
if (gcmd->option_relative) {
gcmd->target.X += startpoint.X;
@ -261,7 +291,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
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)
gcmd->target.X = startpoint.X;
if (gcmd->seen_Y == 0)
@ -288,14 +318,20 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
break;
// G2 - Arc Clockwise
// unimplemented
// G3 - Arc Counter-clockwise
// unimplemented
// G4 - Dwell
case 4:
xoff();
#ifdef XONXOFF
xoff();
#endif
delay_ms(gcmd->P);
xon();
#ifdef XONXOFF
xon();
#endif
break;
// G20 - inches as units
@ -312,6 +348,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
case 30:
enqueue(&gcmd->target);
// no break here, G30 is move and then go home
// G28 - go home
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);
startpoint.X = startpoint.Y = 0;
// move forward a bit
SpecialMoveXY(5 * STEPS_PER_MM_X, 5 * STEPS_PER_MM_Y, FEEDRATE_SLOW_XY);
// 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);
startpoint.Z = 0;
// move out a bit
// move forward a bit
SpecialMoveZ(5 * STEPS_PER_MM_Z, FEEDRATE_SLOW_Z);
// move back into endstop slowly
@ -354,7 +392,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
/*
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;
break;
@ -374,7 +412,7 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
startpoint.X = startpoint.Y = startpoint.Z = startpoint.E = 0;
break;
// TODO: spit an error
// unknown gcode: spit an error
default:
serial_writestr_P(PSTR("E: Bad G-code "));
serwrite_uint8(gcmd->G);
@ -435,14 +473,29 @@ void process_gcode_command(GCODE_COMMAND *gcmd) {
case 106:
WRITE(FAN_PIN, 1);
break;
// M107- fan off
case 107:
WRITE(FAN_PIN, 0);
break;
#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:
serial_writestr_P(PSTR("E: Bad M-code "));
serwrite_uint8(gcmd->M);

View File

@ -5,12 +5,14 @@
#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 {
uint32_t sign :1;
uint32_t mantissa :24;
uint32_t exponent :7;
} decfloat;
// this holds all the possible data from a received command
typedef struct {
uint8_t seen_G :1;
uint8_t seen_M :1;
@ -30,16 +32,26 @@ typedef struct {
uint8_t M;
TARGET target;
uint16_t S;
int16_t S;
uint16_t P;
} GCODE_COMMAND;
// the command being processed
extern GCODE_COMMAND next_target;
// utility functions
int8_t indexof(uint8_t c, const char *string);
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);
// when we have a whole line, feed it to this
void process_gcode_command(GCODE_COMMAND *gcmd);
#endif /* _GCODE_H */

View File

@ -3,8 +3,8 @@
/*
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.
however, a larger movebuffer will probably help with lots of short moves, as each move takes a bunch of math to set up
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 consecutive moves, as each move takes a bunch of math (hence time) to set up
*/
#define MOVEBUFFER_SIZE 8
@ -12,9 +12,11 @@
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 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 X_COG_CIRCUMFERENCE (4.77 * 16.0)
@ -22,6 +24,8 @@
// also try:
// #define XY_COG_RADIUS 9.5
// #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
// 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_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_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))
@ -39,33 +63,19 @@
// 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 FEEDRATE_FAST_XY 6000
#define FEEDRATE_SLOW_XY 300
#define FEEDRATE_FAST_Z 6000
#define FEEDRATE_SLOW_Z 300
#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!
*/
// same as above with 25.4 scale factor
#define STEPS_PER_IN_X ((uint32_t) ((25.4 * X_STEPS_PER_REV / X_COG_CIRCUMFERENCE) + 0.5))
#define STEPS_PER_IN_Y ((uint32_t) ((25.4 * Y_STEPS_PER_REV / Y_COG_CIRCUMFERENCE) + 0.5))
#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))
// 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_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_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
#endif /* _MACHINE_H */

View File

@ -72,8 +72,6 @@ inline void init(void) {
clock_setup();
// set up variables
// slow default
current_position.F = FEEDRATE_SLOW_Z;
memcpy(&startpoint, &current_position, sizeof(TARGET));
memcpy(&(next_target.target), &current_position, sizeof(TARGET));
@ -83,14 +81,10 @@ inline void init(void) {
// say hi to host
serial_writestr_P(PSTR("Start\n"));
// start queue
//enableTimerInterrupt();
}
void clock_250ms(void);
void clock_250ms() {
static uint8_t report = 0;
temp_tick();
if (steptimeout > (30 * 4))
@ -98,18 +92,13 @@ void clock_250ms() {
else
steptimeout++;
report++;
if (report == 4) {
report = 0;
ifclock (CLOCK_FLAG_1S) {
if (DEBUG) {
// current move
serial_writestr_P(PSTR("DDA: f#"));
serwrite_int32(movebuffer[mb_head].f_counter);
serwrite_int32(movebuffer[mb_tail].f_counter);
serial_writechar('/');
// serwrite_uint16(movebuffer[mb_head].f_scale);
// serial_writechar('/');
serwrite_int16(movebuffer[mb_head].f_delta);
serwrite_int16(movebuffer[mb_tail].f_delta);
serial_writechar('\n');
// current position
@ -155,7 +144,7 @@ int main (void)
for (;;)
{
// 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();
scan_char(c);
}
@ -163,66 +152,5 @@ int main (void)
ifclock(CLOCK_FLAG_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();
// }
// }
}
}

View File

@ -39,7 +39,7 @@
#define STEPPER_ENABLE_PIN DIO9
// 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
// OC0B DIO5
// OC1A DIO9
@ -132,7 +132,7 @@
*/
#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 disable_steppers() WRITE(STEPPER_ENABLE_PIN, 1)
// for connection to ATX PSU PWR_ON signal

View File

@ -43,7 +43,6 @@ void ringbuffer_writechar(ringbuffer *buf, uint8_t data)
}
}
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index)
{
return buf->data[_rb_mod(buf->read_pointer + index, buf->size)];

View File

@ -4,6 +4,7 @@
#include <stdint.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
typedef struct {
@ -13,15 +14,19 @@ typedef struct {
volatile RB_BITS data[];
} ringbuffer;
// initialize a ringbuffer
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_canwrite(ringbuffer *buf);
// read bytes
uint8_t ringbuffer_readchar(ringbuffer *buf);
uint8_t ringbuffer_peekchar(ringbuffer *buf, RB_BITS index);
RB_BITS ringbuffer_readblock(ringbuffer *buf, uint8_t *newbuf, RB_BITS size);
// write bytes
void ringbuffer_writechar(ringbuffer *buf, uint8_t data);
RB_BITS ringbuffer_writeblock(ringbuffer *buf, uint8_t *data, RB_BITS size);

View File

@ -121,15 +121,17 @@ void serial_writestr_P(PGM_P data)
serial_writechar(r);
}
void xoff() {
flowflags = FLOWFLAG_SEND_XOFF;
// enable TX interrupt so we can send this character
UCSR0B |= (1 << UDRIE0);
}
#ifdef XONXOFF
void xon() {
if (flowflags & FLOWFLAG_SENT_XOFF)
flowflags = FLOWFLAG_SEND_XON;
// enable TX interrupt so we can send this character
UCSR0B |= (1 << UDRIE0);
}
void xon() {
if (flowflags & FLOWFLAG_SENT_XOFF)
flowflags = FLOWFLAG_SEND_XON;
// enable TX interrupt so we can send this character
UCSR0B |= (1 << UDRIE0);
}
void xoff() {
flowflags = FLOWFLAG_SEND_XOFF;
// enable TX interrupt so we can send this character
UCSR0B |= (1 << UDRIE0);
}
#endif

View File

@ -5,23 +5,31 @@
#include <avr/io.h>
#include <avr/pgmspace.h>
// initialise serial subsystem
void serial_init(void);
// return number of characters in the receive and send buffer
uint16_t serial_rxchars(void);
uint16_t serial_txchars(void);
// read one character
uint8_t serial_popchar(void);
// send one character
void serial_writechar(uint8_t data);
// read/write many characters
uint16_t serial_recvblock(uint8_t *block, int blocksize);
void serial_writeblock(void *data, int datalen);
// write from flash
void serial_writechar_P(PGM_P data);
void serial_writeblock_P(PGM_P data, int datalen);
void serial_writestr_P(PGM_P data);
void xoff(void);
void xon(void);
#ifdef XONXOFF
// XON/XOFF flow control
void xoff(void);
void xon(void);
#endif
#endif /* _SERIAL_H */

View File

@ -3,11 +3,13 @@
#include <stdint.h>
// functions for sending hexadecimal
void serwrite_hex4(uint8_t v);
void serwrite_hex8(uint8_t v);
void serwrite_hex16(uint16_t v);
void serwrite_hex32(uint32_t v);
// functions for sending decimal
#define serwrite_uint8(v) serwrite_uint32(v)
#define serwrite_int8(v) serwrite_int32(v)
#define serwrite_uint16(v) serwrite_uint32(v)

View File

@ -39,8 +39,6 @@ uint8_t temp_flags = 0;
#define TEMP_FLAG_PRESENT 1
#define TEMP_FLAG_TCOPEN 2
#define PID_SCALE 1024L
uint16_t temp_read() {
uint16_t temp;
SPCR = MASK(MSTR) | MASK(SPE);
@ -55,6 +53,10 @@ uint16_t temp_read() {
for (;(SPSR & MASK(SPIF)) == 0;);
temp |= SPDR;
WRITE(SS, 0);
SPCR = 0;
temp_flags = 0;
if ((temp & 0x8002) == 0) {
// got "device id"
@ -69,10 +71,6 @@ uint16_t temp_read() {
}
}
WRITE(SS, 0);
SPCR = 0;
return 0;
}
@ -110,15 +108,26 @@ void temp_tick() {
uint16_t last_temp = current_temp;
temp_read();
int16_t t_delta = target_temp - current_temp;
int16_t t_error = target_temp - current_temp;
// PID stuff
heater_p = t_delta;
heater_i += t_delta;
// note: D follows temp rather than error so there's no large derivative when the target temperature changes
// proportional
heater_p = t_error;
// 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);
uint8_t pid_output = (
// combine factors
int32_t pid_output_intermed = (
(
(((int32_t) heater_p) * p_factor) +
(((int32_t) heater_i) * i_factor) +
@ -126,6 +135,15 @@ void temp_tick() {
) / 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
HEATER_PIN_PWMABLE = pid_output
#else

View File

@ -3,11 +3,31 @@
#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);
// set target temperature
void temp_set(uint16_t t);
// return last read temperature
uint16_t temp_get(void);
// true if last read temp is close to target temp, false otherwise
uint8_t temp_achieved(void);
// send current temperature to host
void temp_print(void);
// periodically read temperature and update heater with PID
void temp_tick(void);
#endif /* _TIMER_H */

View File

@ -7,7 +7,6 @@
#include "dda.h"
ISR(TIMER1_COMPA_vect) {
// WRITE(SCK, 0);
if (movebuffer[mb_tail].live) {
// this interrupt can be interruptible
// TODO: remove when not debugging
@ -19,19 +18,14 @@ ISR(TIMER1_COMPA_vect) {
// cli();
// enableTimerInterrupt();
}
// WRITE(SCK, 1);
// perhaps we can fall directly into dda_start instead of waiting for another step
if (movebuffer[mb_tail].live == 0) {
// fall directly into dda_start instead of waiting for another step
if (movebuffer[mb_tail].live == 0)
next_move();
}
}
void setupTimerInterrupt()
{
//clear the registers
// no outputs
TCCR1A = 0;
// CTC mode
@ -43,6 +37,8 @@ void setupTimerInterrupt()
setTimer(10000);
}
// the following are all from reprap project 5D firmware
uint8_t getTimerResolution(const uint32_t delay)
{
// these also represent frequency: 1000000 / delay / 2 = frequency in hz.
@ -142,7 +138,6 @@ void delay_ms(uint32_t delay) {
delayMicrosecondsInterruptible(delay * 1000);
}
// from reprap project 5D firmware
void delayMicrosecondsInterruptible(uint16_t us)
{
// for a one-microsecond delay, simply return. the overhead

View File

@ -8,13 +8,16 @@
#define US * (F_CPU / 1000000)
#define MS * (F_CPU / 1000)
#define DEFAULT_TICK (100 US)
// #define DEFAULT_TICK (100 US)
#define WAITING_DELAY (10 MS)
void setupTimerInterrupt(void);
uint8_t getTimerResolution(const uint32_t delay);
void setTimerResolution(uint8_t r);
uint16_t getTimerCeiling(const uint32_t delay);
#define setTimerCeiling(c) OCR1A = c
void setTimer(uint32_t delay);
@ -28,6 +31,4 @@ void delayMicrosecondsInterruptible(unsigned int us);
#define enableTimerInterrupt() do { TIMSK1 |= (1<<OCIE1A); } while (0)
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
#define setTimerCeiling(c) OCR1A = c
#endif /* _TIMER_H */