Mattroberts' Firmware

From RepRap
Jump to: navigation, search
Crystal Clear action run.png
Mattroberts' Firmware

Release status: Beta

No image available.png
Description
Firmware
License
Author
Contributors
Based-on
Categories
CAD Models
External Link


Introduction

This page will describe my firmware. At the moment it just contains my acceleration / extruder code. The license for this code sample is CC-by-3.0. The extruder pressure code is in red. The acceleration code is in green.

Config.h

// X and Y are direct drive...
// 16 * 200 steps per revolution, 10 teeth, 5.08mm per tooth
// 16 * 200 / 10 / 5.08 = 62.992126 steps per mm
#define STEPS_PER_MM_X 62.992126
#define STEPS_PER_MM_Y 62.992126

// Z is geared...
// drive gear: 16 * 200 steps per revolution, 10 teeth
// driven gear: 25 teeth, 1.25 mm per revolution (M8 pitch)
// 16 * 200 / 10 * 25 / 1.25 = 6400 steps per mm
#define STEPS_PER_MM_Z 6400

// E...
#define STEPS_PER_CUBIC_MM_E 180
#define INIT_EXTRUSION_AREA (0.465 * 0.31)


// extruder advance constant (s2/mm3)
//
// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2
//
// hooke's law says:		force = k * distance
// bernoulli's priniciple says:	v ^ 2 / 2 + g . h + pressure / density = constant
// so: v ^ 2 is proportional to number of steps we advance the extruder
#define EXTRUDER_ADVANCE_K 0.019



// feedrates (mm/min)
#define INIT_FEEDRATE_MM 4000
#define HOME_FEEDRATE_MM_XY 4000
#define HOME_FEEDRATE_MM_Z 150
#define MIN_FEEDRATE_MM 30

// acceleration (mm/min/s)
#define ACCELERATION 150000L

// steppers to disable after every move
#define AUTO_DISABLE_X 0
#define AUTO_DISABLE_Y 0
#define AUTO_DISABLE_Z 1
#define AUTO_DISABLE_E 0

// stepper directions
#define INVERT_X 1
#define INVERT_Y 1
#define INVERT_Z 0
#define INVERT_E 0

// minimum stepper pulse widths (us)
#define STEP_HIGH_US 1
#define STEP_LOW_US 1

// thermistor
//     +ve --- R2 -+- THERMISTOR -+- gnd
//                 |              |
//     adc --------+----- R1 -----+
#define THERMISTOR_R0_OHMS 100000
#define THERMISTOR_T0_DEG_C 25
#define THERMISTOR_BETA 4036
#define THERMISTOR_R1_OHMS 0      // 0 means missing
#define THERMISTOR_R2_OHMS 4500

// comms
#define UART_BAUD 115200

dda.c

#include <stdint.h>
#include "config.h"
#include "convert.h"
#include "dda.h"
#include "delay.h"
#include "dist.h"
#include "motor.h"
#include "state.h"
#include "uart.h"

#ifdef DEBUG
#undef DEBUG
#define DEBUG(...) __VA_ARGS__
#else
#define DEBUG(...)
#endif

#define q_n 32 // must be a power of 2

#define STATE_IDLE 2
#define STATE_IDLE_SPEEDCHANGE 0
#define STATE_SPEEDCHANGE 1
#define STATE_DDA 3
#define STATE_XYZ 4
#define STATE_E 5
#define STATE_T 6

static struct dda {
    int32_t delta[5], d, f, max_xyze;
} q[q_n];

static uint8_t q_h, q_t;
static int32_t steps_left = -1;
DEBUG(static int32_t count[5];)
static int32_t current_f, step_decel;

static int32_t max(int32_t a, int32_t b) {
    return a > b ? a : b;
}

void dda_q(int32_t *fxyze) {
    int32_t d;

    while (q_h == q_t && steps_left != -1)
        dda_tick();

    DEBUG(uart_puts("dda_q");
          FOREACH_XYZE(i) {
              uart_puts(" "); uart_puti(fxyze[i]);
          }
          uart_puts(" f"); uart_putd(fxyze[F]);
          uart_putc('\n');)

    if (fxyze[X] == 0 && fxyze[Y] == 0 && fxyze[Z] == 0) {
        if (fxyze[E] == 0 || fxyze[E] == UNSEEN)
            return;
        d = convert(fxyze[E], INV_E);
        if (d < 0)
            d = -d;
    } else {
        d = dist_steps(fxyze);
        if (fxyze[E] == UNSEEN)
            fxyze[E] = convert(d, E);
    }

    dda_tick();

    q[q_t].d = 293L * d;
    q[q_t].f = fxyze[F];
    FOREACH_XYZE(i) {
        q[q_t].delta[i] = fxyze[i];
        s.fxyze[i] += fxyze[i];
    }

    DEBUG(uart_puts("d"); uart_putd(d);
          uart_puts(" e"); uart_puti(fxyze[E]);
          uart_puts("\n");)

    q_t = (q_t + 1) & (q_n - 1);
}

void dda_tick(void) {
    static int8_t state = STATE_IDLE;
    static int32_t delta[5], error[5], d, max_xyzet, max_xyze, max_f, e, advance, old_advance, extrusion_rate;

    switch(state++) {
    case STATE_IDLE:
    case STATE_IDLE_SPEEDCHANGE:
        if (q_h == q_t && steps_left == -1) {
            state = STATE_IDLE;
            return;
        }

        if (steps_left == 0) {
            delay_tick(0);
            DEBUG(uart_puts("dda_done");
                  FOREACH_XYZE(i) {
                      uart_puts(" ");
                      uart_puti(count[i]);
                      count[i] = 0;
                  }
                  uart_puts(" ");
                  uart_puti(count[T]);
                  count[T] = 0;
                  uart_puts("\n");)
                
            if (AUTO_DISABLE_X) motor_enable(X, 0);
            if (AUTO_DISABLE_Y) motor_enable(Y, 0);
            if (AUTO_DISABLE_Z) motor_enable(Z, 0);
            if (AUTO_DISABLE_E) motor_enable(E, 0);
            
            steps_left = -1;
            q_h = (q_h + 1) & (q_n - 1);
            if (q_h == q_t) {
                state = STATE_IDLE;
                return;
            }
        }

        if (steps_left == -1) {
            delay_tick(0);
            
            FOREACH_TXYZE(i) {
                delta[i] = q[q_h].delta[i];
                error[i] = 0;
            }
            max_f = q[q_h].f;
            d = q[q_h].d;
            max_xyzet = 0;

            max_xyze = 0;
            steps_left = 0;
            FOREACH_XYZE(i) {
                motor_dir(i, delta[i] >= 0);
                if (delta[i] < 0)
                    delta[i] = -delta[i];
                if (delta[i] != 0)
                    motor_enable(i, 1);
                steps_left += delta[i];
                if (max_xyze < delta[i])
                    max_xyze = delta[i];
            }
            motor_dir(E, 1);
            step_decel = steps_left / 2;
            current_f = MIN_FEEDRATE_MM * 10000L;
            state = STATE_SPEEDCHANGE;
        }
        return;

    case STATE_SPEEDCHANGE:


        state = STATE_DDA;
        delta[T] = d / (current_f >> 11);
        {
            int32_t a = max_xyzet;
            max_xyzet = max(max_xyze, delta[T]);
            a -= max_xyzet;
            a /= 2;
            FOREACH_TXYZE(i)
                error[i] += a;
        }
        return;



    case STATE_DDA:
        FOREACH_TXYZE(a)
            error[a] += delta[a];        
        return;

    case STATE_XYZ:
        FOREACH_XYZ(a)
            if (error[a] > 0) {
                error[a] -= max_xyzet;
                DEBUG(count[a]++);
                motor_step(a);
                steps_left--;
            }
        return;

    case STATE_E:


        e = 0;
        if (error[E] > 0) {
            error[E] -= max_xyzet;
            DEBUG(count[E]++);
            e++;
            steps_left--;
        }
        extrusion_rate = current_f / 600000L;
        extrusion_rate *= s.extrusion_area;
        if (delta[E])
            advance = (int32_t)(STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) * extrusion_rate * extrusion_rate / 10000L;
        else
            advance = 0;
        e += advance - old_advance;
        old_advance = advance;

        if (e != 0) {
            if (e < 0) {
                motor_dir(E, 0);
                e = -e;
            }
            while (e-- > 0) {
                motor_step(E);
                motor_step_done();
            }
            motor_dir(E, 1);
        }
        motor_step_done();
        return;



    case STATE_T:


        state = STATE_IDLE;
        if (error[T] > 0) {    
            error[T] -= max_xyzet;
            DEBUG(count[T]++);

            delay_tick(1);
            if (steps_left < step_decel) {
                if (current_f > MIN_FEEDRATE_MM * 10000L) {
                    current_f -= ACCELERATION;
                    if (current_f < MIN_FEEDRATE_MM * 10000L)
                        current_f = MIN_FEEDRATE_MM * 10000L;
                    state = STATE_IDLE_SPEEDCHANGE;
                }
            } else if (current_f < max_f) {
                current_f += ACCELERATION;
                if (current_f >= max_f) {
                    current_f = max_f;
                    step_decel = step_decel * 2 - steps_left;
                }
                state = STATE_IDLE_SPEEDCHANGE;
            }
            
        }
        return;


    }
}

void dda_drain(void) {
    while (steps_left != -1)
        dda_tick();
}