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)
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
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(',');
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -72,8 +72,6 @@ inline void init(void) {
|
|||
clock_setup();
|
||||
|
||||
// set up variables
|
||||
|
||||
// slow default
|
||||
current_position.F = FEEDRATE_SLOW_Z;
|
||||
memcpy(&startpoint, ¤t_position, sizeof(TARGET));
|
||||
memcpy(&(next_target.target), ¤t_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();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue