time to save again, preliminary PID/PWM support for extruder barrel heater

This commit is contained in:
Michael Moon 2010-01-17 17:46:43 +11:00
parent 411ada4d82
commit 496d58f357
9 changed files with 231 additions and 70 deletions

View File

@ -3,6 +3,31 @@
#include <avr/io.h>
/*
utility functions
*/
#ifndef MASK
#define MASK(PIN) (1 << PIN)
#endif
#define _READ(IO) (RPORT_ ## IO & MASK(PIN_ ## IO))
#define _WRITE(IO, v) if (v) { WPORT_ ## IO |= MASK(PIN_ ## IO); } else { WPORT_ ## IO &= ~MASK(PIN_ ## IO); }
#define _SET_INPUT(IO) (DDR_ ## IO |= MASK(PIN_ ## IO))
#define _SET_OUTPUT(IO) (DDR_ ## IO &= ~MASK(PIN_ ## IO))
// why double up on macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
#define READ(IO) _READ(IO)
#define WRITE(IO, v) _WRITE(IO, v)
#define SET_INPUT(IO) _SET_INPUT(IO)
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
/*
pins
*/
#define PIN_DIO0 PD0
#define RPORT_DIO0 PIND
#define WPORT_DIO0 PORTD

View File

@ -2,6 +2,7 @@
#include <string.h>
#include "pinout.h"
#include "timer.h"
extern struct {
@ -128,7 +129,8 @@ uint32_t approx_distance_3( int32_t dx, int32_t dy, int32_t dz )
*/
void dda_create(TARGET *target, DDA *dda) {
static TARGET startpoint = { 0, 0, 0, 0, 0 };
static TARGET startpoint = { 0, 0, 0, 0, 0 };
uint32_t distance;
// we start at the previous endpoint
// memcpy(&dda->currentpoint, &startpoint, sizeof(TARGET));
@ -145,16 +147,16 @@ void dda_create(TARGET *target, DDA *dda) {
// since it's unusual to combine X, Y and Z changes in a single move on reprap, check if we can use simpler approximations before trying the full 3d approximation.
if (dda->z_delta == 0)
dda->distance = approx_distance(dda->x_delta, dda->y_delta);
distance = approx_distance(dda->x_delta, dda->y_delta);
else if (dda->x_delta == 0 && dda->y_delta == 0)
dda->distance = dda->z_delta;
distance = dda->z_delta;
else
dda->distance = approx_distance_3(dda->x_delta, dda->y_delta, dda->z_delta);
distance = approx_distance_3(dda->x_delta, dda->y_delta, dda->z_delta);
if (dda->distance < 2)
dda->distance = dda->e_delta;
if (dda->distance < 2)
dda->distance = dda->f_delta;
if (distance < 2)
distance = dda->e_delta;
if (distance < 2)
distance = dda->f_delta;
dda->total_steps = dda->x_delta;
if (dda->y_delta > dda->total_steps)
@ -194,7 +196,7 @@ void dda_create(TARGET *target, DDA *dda) {
// mm (distance) * 60000000 us/min / step (total_steps) = mm.us per step.min
// so in the interrupt we must simply calculate
// mm.us per step.min / mm per min (F) = us per step
dda->move_duration = dda->distance * 60000000 / dda->total_steps;
dda->move_duration = distance * 60000000 / dda->total_steps;
// next dda starts where we finish
memcpy(&startpoint, &dda->endpoint, sizeof(TARGET));

View File

@ -35,7 +35,6 @@ typedef struct {
uint32_t total_steps;
uint16_t f_scale;
uint32_t distance;
uint32_t move_duration;
} DDA;

View File

@ -4,6 +4,7 @@
#include "machine.h"
#include "dda.h"
#include "serial.h"
extern uint8_t option_bitfield;
@ -76,13 +77,8 @@ void scan_char(uint8_t c) {
next_target.target.E = manexp_to_float(mantissa, exp) * STEPS_PER_MM_E;
break;
case 'F':
// TODO: calculate end speed in microseconds per step from millimeters per minute
// MM = sqrt(X^2 + Y^2)
// STEPS = max(X * STEPS_PER_MM_X, Y * STEPS_PER_MM_Y)
// DURATION = MM / MM_PER_MIN * 60 SEC_PER_MIN * 1000000 US_PER_SEC
// US/STEP = DURATION / STEPS
// intF = sqrt(X^2 + Y^2) / max(X * STEPS_PER_MM_X, Y * STEPS_PER_MM_Y)
next_target.target.F = manexp_to_float(mantissa, exp) * STEPS_PER_MM_F;
// just save an integer value for F, 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 = mantissa;
break;
}
mantissa = 0;
@ -122,6 +118,8 @@ void scan_char(uint8_t c) {
last_field = 0;
memset(&next_target, 0, sizeof(GCODE_COMMAND));
next_target.option = option_bitfield;
serial_writeblock((uint8_t *) "OK\n", 3);
break;
}
}

View File

@ -4,7 +4,9 @@
/*
machine variables
*/
#define MOVEBUFFER_SIZE 8
/*
axis calculations, adjust as necessary
*/
@ -17,27 +19,18 @@
#define EXTRUDER_INLET_DIAMETER 3
#define EXTRUDER_NOZZLE_DIAMETER 0.8
#define STEPS_PER_MM_X (XY_STEPS_PER_REV * XY_COG_CIRCUMFERENCE)
#define STEPS_PER_MM_Y (XY_STEPS_PER_REV * XY_COG_CIRCUMFERENCE)
#define STEPS_PER_MM_Z (3200)
#define STEPS_PER_MM_E (EXTRUDER_STEPS_PER_REV * EXTRUDER_SHAFT_RADIUS * PI * EXTRUDER_INLET_DIAMETER / EXTRUDER_NOZZLE_DIAMETER)
#define STEPS_PER_MM_PER_S_F (3200)
#define STEPS_PER_MM_F STEPS_PER_MM_PER_S_F
/*
F is sent in units of millimeters per second
and implemented as microseconds per step
MM/S * steps/mm * 1000000us/s = steps per microsecond
heater PID variables
used as int16_t * FACTOR so don't put brackets around them
*/
#define FAST_MM_PER_SEC 40
#define SLOW_MM_PER_SEC 20
#define ACCEL 10
#define P_FACTOR 133 / 1024
#define I_FACTOR 17 / 1024
#define D_FACTOR 180 / 1024
#endif /* _MACHINE_H */

View File

@ -3,58 +3,118 @@
#include "arduino.h"
#ifndef MASK
#define MASK(PIN) (1 << PIN)
#endif
/*
Machine Pin Definitions
*/
#define READ(IO) (RPORT_ ## IO & MASK(PIN_ ## IO))
#define WRITE(IO, v) if (v) { WPORT_ ## IO |= MASK(PIN_ ## IO); } else { WPORT_ ## IO &= ~MASK(PIN_ ## IO); }
// RXD DIO0
// TXD DIO1
#define SET_INPUT(IO) (DDR_ ## IO |= MASK(PIN_ ## IO))
#define SET_OUTPUT(IO) (DDR_ ## IO &= ~MASK(PIN ## IO))
#define X_STEP_PIN AIO0
#define X_DIR_PIN AIO1
#define X_MIN_PIN AIO2
#define _x_step(st) WRITE(AIO0, st)
#define Y_STEP_PIN AIO3
#define Y_DIR_PIN AIO4
#define Y_MIN_PIN AIO5
#define Z_STEP_PIN DIO5
#define Z_DIR_PIN DIO6
#define Z_MIN_PIN DIO7
#define E_STEP_PIN DIO2
#define E_DIR_PIN DIO3
// list of PWM-able pins
// OC0A DIO6
// OC0B DIO5
// OC1A DIO9
// OC1B DIO10
// OC2A DIO11
// OC2B DIO3
#define HEATER_PIN DIO6
#define HEATER_PIN_PWM OC0A
#define SCK DIO13
#define MISO DIO12
#define MOSI DIO11
#define SS DIO10
/*
X Stepper
*/
#define _x_step(st) WRITE(X_STEP_PIN, st)
#define x_step() _x_step(1);
#define x_direction(dir) WRITE(AIO1, dir)
#define x_min() READ(AIO2)
#ifdef MAX_ENDSTOPS
#define x_max() READ(AIO3)
#define x_direction(dir) WRITE(X_DIR_PIN, dir)
#define x_min() READ(X_MIN_PIN)
#ifdef X_MAX_PIN
#define x_max() READ(X_MAX_PIN)
#else
#define x_max() (0)
#define x_max() (0)
#endif
#define _y_step(st) WRITE(DIO2, st)
/*
Y Stepper
*/
#define _y_step(st) WRITE(Y_STEP_PIN, st)
#define y_step() _y_step(1);
#define y_direction(dir) WRITE(DIO3, dir)
#define y_min() READ(DIO4)
#ifdef MAX_ENDSTOPS
#define y_max() READ(DIO5)
#define y_direction(dir) WRITE(Y_DIR_PIN, dir)
#define y_min() READ(Y_MIN_PIN)
#ifdef Y_MAX_PIN
#define y_max() READ(Y_MAX_PIN)
#else
#define y_max() (0)
#define y_max() (0)
#endif
#define _z_step(st) WRITE(DIO6, st)
/*
Z Stepper
*/
#define _z_step(st) WRITE(Z_STEP_PIN, st)
#define z_step() _z_step(1);
#define z_direction(dir) WRITE(DIO7, dir)
#define z_min() READ(DIO8)
#ifdef MAX_ENDSTOPS
#define z_max() READ(DIO9)
#define z_direction(dir) WRITE(Z_DIR_PIN, dir)
#define z_min() READ(Z_MIN_PIN)
#ifdef Z_MAX_PIN
#define z_max() READ(Z_MAX_PIN)
#else
#define z_max() (0)
#define z_max() (0)
#endif
#define _e_step(st) WRITE(AIO4, st)
/*
Extruder
*/
#define _e_step(st) WRITE(E_STEP_PIN, st)
#define e_step() _e_step(1);
#define e_direction(dir) WRITE(AIO5, dir)
#define e_direction(dir) WRITE(E_DIR_PIN, dir)
#define enable_steppers() WRITE(DIO10, 1)
#define disable_steppers() WRITE(DIO10, 0)
/*
Heater
*/
inline void unstep(void) {
_x_step(0);
_y_step(0);
_z_step(0);
_e_step(0);
}
#define enable_heater() WRITE(HEATER_PIN, 1)
#define disable_heater() WRITE(HEATER_PIN, 0)
/*
Stepper Enable (ATX PSU pwr_good signal?)
*/
#ifdef STEPPER_ENABLE_PIN
#define enable_steppers() WRITE(STEPPER_ENABLE_PIN, 1)
#define disable_steppers() WRITE(STEPPER_ENABLE_PIN, 0)
#else
#define enable_steppers() if (0) {}
#define disable_steppers() if (0) {}
#endif
/*
End Step - All Steppers
(so we don't have to delay in interrupt context)
*/
#define unstep() do { _x_step(0); _y_step(0); _z_step(0); _e_step(0); } while (0)
#endif /* _PINOUT_H */

76
mendel/temp.c Normal file
View File

@ -0,0 +1,76 @@
#include "temp.h"
#include "machine.h"
#include "pinout.h"
uint16_t current_temp;
uint16_t target_temp;
int16_t heater_p;
int16_t heater_i;
int16_t heater_d;
void temp_setup() {
SET_OUTPUT(SCK);
SET_INPUT(MISO);
SET_OUTPUT(SS);
WRITE(SS, 0);
WRITE(SCK, 0);
}
uint16_t temp_read() {
uint16_t temp;
SPCR = MASK(MSTR) | MASK(SPE);
SPDR = 0;
for (;(SPSR & MASK(SPIF)) == 0;);
temp = SPDR << 8;
SPDR = 0;
for (;(SPSR & MASK(SPIF)) == 0;);
temp |= SPDR;
if ((temp & 0x8002) == 0) {
// got "device id"
if (temp & 4) {
// thermocouple open
}
else {
current_temp = temp >> 3;
return current_temp;
}
}
return 0;
}
void temp_set(uint16_t t) {
target_temp = t;
}
void temp_tick() {
uint16_t last_temp = current_temp;
temp_read();
int16_t t_delta = 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
heater_d = (current_temp - last_temp);
int16_t pid_output = (heater_p * P_FACTOR) + (heater_i * I_FACTOR) + (heater_d * D_FACTOR);
#ifdef HEATER_PIN_PWMABLE
HEATER_PIN_PWMABLE = pid_output
#else
if (pid_output > 0) {
enable_heater();
}
else {
disable_heater();
}
#endif
}

11
mendel/temp.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _TEMP_H
#define _TEMP_H
#include <stdint.h>
void temp_setup(void);
uint16_t temp_read(void);
void temp_set(uint16_t t);
void temp_tick(void);
#endif /* _TIMER_H */

View File

@ -31,9 +31,6 @@ inline void disableTimerInterrupt(void)
TIMSK1 &= ~(1<<OCIE1A);
}
inline void setTimerCeiling(uint16_t c)
{
OCR1A = c;
}
#define setTimerCeiling(c) OCR1A = c
#endif /* _TIMER_H */