diff --git a/Makefile b/Makefile index a68da2f..c5a2cb8 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ PROGRAM = mendel -SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c +SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c intercom.c ############################################################################## # # @@ -68,10 +68,12 @@ OBJCOPY = $(ARCH)objcopy # enables reprap-style acceleration # # ACCELERATION_RAMPING # # enables start/stop ramping # +# GEN3 # +# build for standard reprap electronics instead of your custom rig # # # ############################################################################## -DEFS = -DF_CPU=$(F_CPU) +DEFS = -DF_CPU=$(F_CPU) -DHOST -DGEN3 # DEFS += "-DDEBUG=1" OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once @@ -115,9 +117,9 @@ clean: size: $(PROGRAM).elf @echo " SIZE Atmega168 Atmega328p Atmega644" - @$(OBJDUMP) -h $^ | perl -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (14 * 1024), 14, $$a * 100 / (30 * 1024), 30, $$a * 100 / (63 * 1024), 63 }' - @$(OBJDUMP) -h $^ | perl -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (4 * 1024), 4 }' - @$(OBJDUMP) -h $^ | perl -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (2 * 1024), 2 }' + @$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (14 * 1024)), 14, ceil($$a * 100 / (30 * 1024)), 30, ceil($$a * 100 / (63 * 1024)), 63 }' + @$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (4 * 1024)), 4 }' + @$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (2 * 1024)), 2 }' config.h: config.h.dist @echo "Please review config.h, as config.h.dist is more recent." diff --git a/config.h.dist b/config.h.dist index 20db5c0..b9cdcf8 100644 --- a/config.h.dist +++ b/config.h.dist @@ -46,14 +46,14 @@ Each movement starts at the speed of the previous command and accelerates or decelerates linearly to reach target speed at the end of the movement. Can also be set in Makefile */ -#define ACCELERATION_REPRAP +// #define ACCELERATION_REPRAP /* acceleration and deceleration ramping. Each movement starts at (almost) no speed, linearly accelerates to target speed and decelerates just in time to smoothly stop at the target. alternative to ACCELERATION_REPRAP Can also be set in Makefile */ -//#define ACCELERATION_RAMPING +#define ACCELERATION_RAMPING // how fast to accelerate when using ACCELERATION_RAMPING // smaller values give quicker acceleration @@ -68,7 +68,7 @@ // which temperature sensor are you using? // #define TEMP_MAX6675 -#define TEMP_THERMISTOR +// #define TEMP_THERMISTOR // #define TEMP_AD595 #define NUM_TEMP_SENSORS 1 @@ -80,6 +80,9 @@ * If your temperature sensor has no associated heater, enter '255' as the * * heater index. * * * +* for GEN3 set temp_type to TT_INTERCOM, temp_pin to 0 and heater index to * +* 255 * +* * \***************************************************************************/ struct { @@ -90,14 +93,14 @@ struct { } temp_sensors[NUM_TEMP_SENSORS] = { { - TT_MAX6675, + TT_INTERCOM, 0, 0 } }; #endif -#define NUM_HEATERS 1 +#define NUM_HEATERS 0 #ifdef HEATER_C /***************************************************************************\ * * @@ -119,7 +122,7 @@ struct { { { &PORTD, - PIND0, + PIND6, &OCR0A } }; @@ -238,6 +241,12 @@ struct { #define STEPPER_ENABLE_PIN DIO9 +#ifdef GEN3 + #define TX_ENABLE_PIN AIO2 + #define RX_ENABLE_PIN DIO4 + #define DEBUG_LED DIO13 +#endif + /** * list of PWM-able pins and corresponding timers * timer1 is used for step timing so don't use OC1A/OC1B @@ -273,14 +282,7 @@ struct { * */ - -// comment out the ones you don't have -#define HEATER_PIN DIO6 -#define HEATER_PWM OCR0A - -#define FAN_PIN DIO5 -#define FAN_PWM OCR0B - +// this is the scaling of internally stored PID values. 1024L is a good value #define PID_SCALE 1024L // -------------------------------------------------------------------------- diff --git a/extruder/Makefile b/extruder/Makefile new file mode 100644 index 0000000..56ddf6a --- /dev/null +++ b/extruder/Makefile @@ -0,0 +1,142 @@ +############################################################################## +# # +# FiveD on Arduino - alternative firmware for repraps # +# # +# by Triffid Hunter, Traumflug, jakepoz # +# # +# # +# This firmware is Copyright (C) 2009-2010 Michael Moon aka Triffid_Hunter # +# # +# This program is free software; you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the Free Software # +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # +# # +############################################################################## + +############################################################################## +# # +# Change these to suit your application # +# # +############################################################################## + +PROGRAM = extruder + +SOURCES = $(PROGRAM).c intercom.c delay.c analog.c watchdog.c + +############################################################################## +# # +# Change these to suit your hardware # +# # +############################################################################## + +MCU_TARGET = atmega168 +F_CPU = 16000000L + +############################################################################## +# # +# These defaults should be ok, change if you need to # +# # +############################################################################## + +ARCH = avr- +CC = $(ARCH)gcc +OBJDUMP = $(ARCH)objdump +OBJCOPY = $(ARCH)objcopy + +############################################################################## +# # +# Available Defines: # +# # +# DEBUG # +# enables tons of debugging output. may cause host-side talkers to choke # +# XONXOFF # +# enables XON/XOFF flow control for stupid or crude talkers # +# ACCELERATION_REPRAP # +# enables reprap-style acceleration # +# ACCELERATION_RAMPING # +# enables start/stop ramping # +# # +############################################################################## + +DEFS = -DF_CPU=$(F_CPU) -DEXTRUDER -DGEN3 +# DEFS += "-DDEBUG=1" + +OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once +# OPTIMIZE = -O0 +CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps +LDFLAGS = -Wl,--as-needed -Wl,--gc-sections + +AVRDUDE = avrdude +AVRDUDECONF = /etc/avrdude.conf + +############################################################################## +# # +# udev rule for /dev/arduino (insert into /etc/udev/rules.d/99-local.rules) # +# SUBSYSTEMS=="usb", ATTRS{idProduct}=="6001", ATTRS{idVendor}=="0403", # +# NAME="%k", SYMLINK+="arduino", SYMLINK+="arduino_$attr{serial}", # +# MODE="0660" # +# # +############################################################################## +PROGPORT = /dev/arduino +PROGBAUD = 57600 + +OBJ = $(patsubst %.c,%.o,${SOURCES}) + +.PHONY: all program clean size +.PRECIOUS: %.o %.elf + +all: config.h $(PROGRAM).hex $(PROGRAM).lst $(PROGRAM).sym size + +program: $(PROGRAM).hex config.h + stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + @sleep 0.1 + @stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) + $(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U flash:w:$^ + stty 115200 raw ignbrk -hup -echo ixoff < $(PROGPORT) + +clean: + rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~ + +size: $(PROGRAM).elf + @echo " SIZE Atmega168 Atmega328p Atmega644" + @$(OBJDUMP) -h $^ | perl -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (14 * 1024), 14, $$a * 100 / (30 * 1024), 30, $$a * 100 / (63 * 1024), 63 }' + @$(OBJDUMP) -h $^ | perl -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (4 * 1024), 4 }' + @$(OBJDUMP) -h $^ | perl -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (2 * 1024), 2 }' + +config.h: config.h.dist + @echo "Please review config.h, as config.h.dist is more recent." + @false + +%.o: %.c config.h + @echo " CC $@" + @$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $(subst .o,.c,$@) + +%.elf: $(OBJ) + @echo " LINK $@" + @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.lst: %.elf + @echo " OBJDUMP $@" + @$(OBJDUMP) -h -S $< > $@ + +%.hex: %.elf + @echo " OBJCOPY $@" + @$(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.bin: %.elf + @echo " OBJCOPY $@" + @$(OBJCOPY) -j .text -j .data -O binary $< $@ + +%.sym: %.elf + @echo " SYM $@" + @$(OBJDUMP) -t $< | perl -ne 'BEGIN { printf " ADDR NAME SIZE\n"; } /([0-9a-f]+)\s+(\w+)\s+O\s+\.(bss|data)\s+([0-9a-f]+)\s+(\w+)/ && printf "0x%04x %-20s +%d\n", eval("0x$$1") & 0xFFFF, $$5, eval("0x$$4")' | sort -k1 > $@ diff --git a/extruder/README b/extruder/README new file mode 100644 index 0000000..3d313a2 --- /dev/null +++ b/extruder/README @@ -0,0 +1,2 @@ +Reprap Gen3 extruder controller support for Triffid_Hunter's FiveD_on_Arduino firmware +by jakepoz diff --git a/extruder/analog.c b/extruder/analog.c new file mode 120000 index 0000000..4ba410b --- /dev/null +++ b/extruder/analog.c @@ -0,0 +1 @@ +../analog.c \ No newline at end of file diff --git a/extruder/analog.h b/extruder/analog.h new file mode 120000 index 0000000..882b768 --- /dev/null +++ b/extruder/analog.h @@ -0,0 +1 @@ +../analog.h \ No newline at end of file diff --git a/extruder/arduino.h b/extruder/arduino.h new file mode 120000 index 0000000..14df5af --- /dev/null +++ b/extruder/arduino.h @@ -0,0 +1 @@ +../arduino.h \ No newline at end of file diff --git a/extruder/arduino_168_328p.h b/extruder/arduino_168_328p.h new file mode 120000 index 0000000..3940ca5 --- /dev/null +++ b/extruder/arduino_168_328p.h @@ -0,0 +1 @@ +../arduino_168_328p.h \ No newline at end of file diff --git a/extruder/config.h.dist b/extruder/config.h.dist new file mode 100644 index 0000000..b11dfb8 --- /dev/null +++ b/extruder/config.h.dist @@ -0,0 +1,79 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include "arduino.h" + +//RS485 Interface pins +#define RX_ENABLE_PIN DIO4 +#define TX_ENABLE_PIN AIO2 + +// Control pins for the A3949 chips +#define H1D DIO7 +#define H1E DIO5 +#define H2D DIO8 +#define H2E DIO6 + +// PWM versions of the enable_pins +#define H1E_PWM OCR0B +#define H2E_PWM OCR0A + +//Step/Dir Pins from motherboard to extruder +//IMPORTANT: Assumes that the step pin is on PCIE0 +#define E_STEP_PIN DIO10 +#define E_DIR_PIN DIO9 + +//Trimpot is on AIO0, pin 23 +#define TRIM_POT AIO0 +#define TRIM_POT_CHANNEL 0 + +//Debug LED will blink on RS485 transmission +#define DEBUG_LED DIO13 + +//Read analog voltage from thermistor +#define TEMP_PIN AIO3 +#define TEMP_PIN_CHANNEL 3 + +#define REFERENCE REFERENCE_AVCC + +// list of PWM-able pins and corresponding timers +// timer1 is used for step timing so don't use OC1A/OC1B (DIO9/DIO10) +// OC0A DIO6 +// OC0B DIO5 +// OC1A DIO9 +// OC1B DIO10 +// OC2A DIO11 +// OC2B DIO3 + +#define HEATER_PIN DIO11 +#define HEATER_PWM OCR2A + +#define BED_PIN DIO12 + +#define ANALOG_MASK (MASK(TRIM_POT_CHANNEL) | MASK(TEMP_PIN_CHANNEL)) + +/* + Intercom +*/ +#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0) +#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0) + +/* + Motors +*/ + +#define enable_motors() do { TCCR0A |= MASK(COM0A1) | MASK(COM0B1); } while (0) +#define disable_motors() do { TCCR0A &= ~MASK(COM0A1) & ~MASK(COM0B1); } while (0) + +/* + Heater +*/ + +#ifdef HEATER_PWM + #define enable_heater() do { TCCR2A |= MASK(COM2A1); } while (0) + #define disable_heater() do { TCCR2A &= ~MASK(COM2A1); } while (0) +#else + #define enable_heater() WRITE(HEATER_PIN, 1) + #define disable_heater() WRITE(HEATER_PIN, 0) +#endif + +#endif /* _CONFIG_H */ diff --git a/extruder/delay.c b/extruder/delay.c new file mode 120000 index 0000000..1df3093 --- /dev/null +++ b/extruder/delay.c @@ -0,0 +1 @@ +../delay.c \ No newline at end of file diff --git a/extruder/delay.h b/extruder/delay.h new file mode 120000 index 0000000..8c2af90 --- /dev/null +++ b/extruder/delay.h @@ -0,0 +1 @@ +../delay.h \ No newline at end of file diff --git a/extruder/extruder.c b/extruder/extruder.c new file mode 100644 index 0000000..7d11b70 --- /dev/null +++ b/extruder/extruder.c @@ -0,0 +1,229 @@ +#include +#include + +#include + +#include "intercom.h" +#include "analog.h" +#include "config.h" +#include "watchdog.h" + +static uint8_t motor_pwm; + +#define NUMTEMPS 20 +short temptable[NUMTEMPS][2] = { + {1, 841}, + {54, 255}, + {107, 209}, + {160, 184}, + {213, 166}, + {266, 153}, + {319, 142}, + {372, 132}, + {425, 124}, + {478, 116}, + {531, 108}, + {584, 101}, + {637, 93}, + {690, 86}, + {743, 78}, + {796, 70}, + {849, 61}, + {902, 50}, + {955, 34}, + {1008, 3} +}; + +void io_init(void) { + // setup I/O pins + WRITE(DEBUG_LED, 0); SET_OUTPUT(DEBUG_LED); + WRITE(H1D,0); SET_OUTPUT(H1D); + WRITE(H1E,0); SET_OUTPUT(H1E); + WRITE(H2D,0); SET_OUTPUT(H2D); + WRITE(H2E,0); SET_OUTPUT(H2E); + + SET_INPUT(TRIM_POT); + SET_INPUT(TEMP_PIN); + SET_INPUT(E_STEP_PIN); + SET_INPUT(E_DIR_PIN); + + //Enable the RS485 transceiver + SET_OUTPUT(RX_ENABLE_PIN); + SET_OUTPUT(TX_ENABLE_PIN); + disable_transmit(); + + #ifdef HEATER_PIN + WRITE(HEATER_PIN, 0); SET_OUTPUT(HEATER_PIN); + #endif + + #ifdef BED_PIN + WRITE(BED_PIN, 0); SET_OUTPUT(BED_PIN); + #endif + + #if defined(HEATER_PWM) || defined(FAN_PWM) || defined(BED_PWM) + // setup PWM timer: fast PWM, no prescaler + TCCR2A = MASK(WGM21) | MASK(WGM20); + TCCR2B = MASK(CS22); + TIMSK2 = 0; + OCR2A = 0; + OCR2B = 0; + #endif + + #if defined(H1E_PWM) && defined(H2E_PWM) + TCCR0A = MASK(WGM01) | MASK(WGM00); + TCCR0B = MASK(CS20); + TIMSK0 = 0; + OCR0A = 0; + OCR0B = 0; + #endif +} + +void motor_init(void) { + //Enable an interrupt to be triggered when the step pin changes + //This will be PCIE0 + PCICR = MASK(PCIE0); + PCMSK0 = MASK(PCINT2); +} + +ISR(PCINT0_vect) { + static uint8_t coil_pos, pwm, flag; + + if (flag == 1) flag = 0; + else flag = 1; + + //if the step pin is high, we advance the motor + if (flag) { + + //Turn on motors only on first tick to save power I guess + enable_motors(); + + //Advance the coil position + if (READ(E_DIR_PIN)) + coil_pos++; + else + coil_pos--; + + coil_pos &= 31; + + //Grab the latest motor power to use + pwm = motor_pwm; + + switch(coil_pos >> 2) { + case 0: + WRITE(H1D, 0); + WRITE(H2D, 0); + H1E_PWM = 0; + H2E_PWM = pwm; + break; + case 1: + WRITE(H1D, 1); + WRITE(H2D, 0); + H1E_PWM = pwm; + H2E_PWM = pwm; + break; + case 2: + WRITE(H1D, 1); + WRITE(H2D, 0); + H1E_PWM = pwm; + H2E_PWM = 0; + break; + case 3: + WRITE(H1D, 1); + WRITE(H2D, 1); + H1E_PWM = pwm; + H2E_PWM = pwm; + break; + case 4: + WRITE(H1D, 1); + WRITE(H2D, 1); + H1E_PWM = 0; + H2E_PWM = pwm; + break; + case 5: + WRITE(H1D, 0); + WRITE(H2D, 1); + H1E_PWM = pwm; + H2E_PWM = pwm; + break; + case 6: + WRITE(H1D, 0); + WRITE(H2D, 1); + H1E_PWM = pwm; + H2E_PWM = 0; + break; + case 7: + WRITE(H1D, 0); + WRITE(H2D, 0); + H1E_PWM = pwm; + H2E_PWM = pwm; + break; + } + } +} + +void init(void) { + // set up watchdog + wd_init(); + + // setup analog reading + analog_init(); + + // set up serial + intercom_init(); + + // set up inputs and outputs + io_init(); + + // set up extruder motor driver + motor_init(); + + // enable interrupts + sei(); + + // reset watchdog + wd_reset(); +} + + +int main (void) +{ + static uint8_t i; + static uint16_t raw_temp; + + init(); + + enable_heater(); + + start_send(); + + // main loop + for (;;) + { + wd_reset(); + + //Read motor PWM + motor_pwm = analog_read(TRIM_POT_CHANNEL) >> 2; + + //Read current temperature + raw_temp = analog_read(TEMP_PIN_CHANNEL); + + //Calculate real temperature based on lookup table + for (i = 1; i < NUMTEMPS; i++) { + if (temptable[i][0] > raw_temp) { + raw_temp = temptable[i][1] + + (temptable[i][0] - raw_temp) * (temptable[i-1][1] - temptable[i][1]) / (temptable[i][0] - temptable[i-1][0]); + + break; + } + } + + //Clamp for overflows + if (i == NUMTEMPS) raw_temp = temptable[NUMTEMPS-1][1]; + if (raw_temp > 255) raw_temp = 255; + + //Update the intercom values + update_send_cmd(raw_temp); + + HEATER_PWM = get_read_cmd(); + } +} diff --git a/extruder/intercom.c b/extruder/intercom.c new file mode 100644 index 0000000..35cd1f3 --- /dev/null +++ b/extruder/intercom.c @@ -0,0 +1,220 @@ +#ifdef GEN3 + +#include "intercom.h" + +#include + +#include "config.h" +#include "delay.h" + +#define INTERCOM_BAUD 57600 + +#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0) +#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0) + +/* + Defines a super simple intercom interface using the RS485 modules + + Host will say: START1 START2 PWM_CMD PWM_CHK + Extruder will reply: START1 START2 TMP_CMD TMP_CHK + + CHK = 255-CMD, if they match do the work, if not, ignore this packet + + in a loop +*/ + + +#define START1 0xAA +#define START2 0x55 + +typedef enum { + SEND_START1, + SEND_START2, + SEND_CMD, + SEND_CHK, + SEND_DONE, + + READ_START1, + READ_START2, + READ_CMD, + READ_CHK, +} intercom_state_e; + + +intercom_state_e state = READ_START1; +uint8_t cmd, chk, send_cmd, read_cmd; + +void intercom_init(void) +{ +#ifdef HOST + #if INTERCOM_BAUD > 38401 + UCSR1A = MASK(U2X1); + UBRR1 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5); + #else + UCSR1A = 0; + UBRR1 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5); + #endif + UCSR1B = MASK(RXEN1) | MASK(TXEN1); + UCSR1C = MASK(UCSZ11) | MASK(UCSZ10); + + UCSR1B |= MASK(RXCIE1) | MASK(TXCIE1); +#else + #if INTERCOM_BAUD > 38401 + UCSR0A = MASK(U2X0); + UBRR0 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5); + #else + UCSR0A = 0; + UBRR0 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5); + #endif + UCSR0B = MASK(RXEN0) | MASK(TXEN0); + UCSR0C = MASK(UCSZ01) | MASK(UCSZ00); + + UCSR0B |= MASK(RXCIE0) | MASK(TXCIE0); +#endif +} + +void update_send_cmd(uint8_t new_send_cmd) { + send_cmd = new_send_cmd; +} + +uint8_t get_read_cmd(void) { + return read_cmd; +} + +static void write_byte(uint8_t val) { +#ifdef HOST + UDR1 = val; +#else + UDR0 = val; +#endif +} + + +void start_send(void) { + state = SEND_START1; + enable_transmit(); + delay_us(15); + //Enable interrupts so we can send next characters +#ifdef HOST + UCSR1B |= MASK(UDRIE1); +#else + UCSR0B |= MASK(UDRIE0); +#endif +} + +static void finish_send(void) { + state = READ_START1; + disable_transmit(); +} + + +/* + Interrupts, UART 0 for mendel +*/ +#ifdef HOST +ISR(USART1_RX_vect) +#else +ISR(USART_RX_vect) +#endif +{ + static uint8_t c; + +#ifdef HOST + c = UDR1; + UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1); +#else + c = UDR0; + UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0); +#endif + + if (state >= READ_START1) { + + switch(state) { + case READ_START1: + if (c == START1) state = READ_START2; + break; + case READ_START2: + if (c == START2) state = READ_CMD; + else state = READ_START1; + break; + case READ_CMD: + cmd = c; + state = READ_CHK; + break; + case READ_CHK: + chk = c; + + if (chk == 255 - cmd) { + //Values are correct, do something useful + WRITE(DEBUG_LED,1); + read_cmd = cmd; +#ifdef EXTRUDER + start_send(); +#endif + } + else + { + state = READ_START1; + } + break; + default: + break; + } + } + +} + +#ifdef HOST +ISR(USART1_TX_vect) +#else +ISR(USART_TX_vect) +#endif +{ + if (state == SEND_DONE) { + finish_send(); + + +#ifdef HOST + UCSR1B &= ~MASK(TXCIE1); +#else + UCSR0B &= ~MASK(TXCIE0); +#endif + } +} + +#ifdef HOST +ISR(USART1_UDRE_vect) +#else +ISR(USART_UDRE_vect) +#endif +{ + switch(state) { + case SEND_START1: + write_byte(START1); + state = SEND_START2; + break; + case SEND_START2: + write_byte(START2); + state = SEND_CMD; + break; + case SEND_CMD: + write_byte(send_cmd); + state = SEND_CHK; + break; + case SEND_CHK: + write_byte(255 - send_cmd); + state = SEND_DONE; +#ifdef HOST + UCSR1B &= ~MASK(UDRIE1); + UCSR1B |= MASK(TXCIE1); +#else + UCSR0B &= ~MASK(UDRIE0); + UCSR0B |= MASK(TXCIE0); +#endif + break; + default: + break; + } +} + +#endif /* GEN3 */ diff --git a/extruder/intercom.h b/extruder/intercom.h new file mode 100644 index 0000000..5a6ab8e --- /dev/null +++ b/extruder/intercom.h @@ -0,0 +1,17 @@ +#ifndef _INTERCOM_H +#define _INTERCOM_H + +#include + +// initialise serial subsystem +void intercom_init(void); + +//Update the message we are sending over intercom +void update_send_cmd(uint8_t new_send_cmd); + +void start_send(void); + +//Read the message we are receiving over intercom +uint8_t get_read_cmd(void); + +#endif /* _INTERCOM_H */ diff --git a/extruder/watchdog.c b/extruder/watchdog.c new file mode 120000 index 0000000..f5d6bfa --- /dev/null +++ b/extruder/watchdog.c @@ -0,0 +1 @@ +../watchdog.c \ No newline at end of file diff --git a/extruder/watchdog.h b/extruder/watchdog.h new file mode 120000 index 0000000..20df3e8 --- /dev/null +++ b/extruder/watchdog.h @@ -0,0 +1 @@ +../watchdog.h \ No newline at end of file diff --git a/gcode_parse.c b/gcode_parse.c index 53e0de1..343656c 100644 --- a/gcode_parse.c +++ b/gcode_parse.c @@ -192,11 +192,9 @@ void gcode_parse_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.M == 109)) next_target.S = decfloat_to_int(&read_digit, 4, 1); - #ifdef HEATER_PIN // 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); - #endif else next_target.S = decfloat_to_int(&read_digit, 1, 1); if (debug_flags & DEBUG_ECHO) diff --git a/gcode_process.c b/gcode_process.c index 542d064..4e1a9d9 100644 --- a/gcode_process.c +++ b/gcode_process.c @@ -199,7 +199,6 @@ void process_gcode_command() { case 104: temp_set(next_target.P, next_target.S); if (next_target.S) { - enable_heater(); power_on(); } else { @@ -213,15 +212,15 @@ void process_gcode_command() { break; // M106- fan on - #ifdef FAN_PIN + #if NUM_HEATERS > 1 case 106: - enable_fan(); + heater_set(1, 255); break; // M107- fan off case 107: - disable_fan(); + heater_set(1, 0); break; - #endif + #endif // M109- set temp and wait case 109: @@ -262,7 +261,7 @@ void process_gcode_command() { serial_writestr_P(PSTR("FIRMWARE_NAME:FiveD_on_Arduino FIRMWARE_URL:http%3A//github.com/triffid/FiveD_on_Arduino/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1 HEATER_COUNT:1\n")); break; - #ifdef HEATER_PIN + #if NUM_HEATERS > 0 // M130- heater P factor case 130: if (next_target.seen_S) @@ -291,7 +290,7 @@ void process_gcode_command() { case 134: heater_save_settings(); break; - #endif /* HEATER_PIN */ + #endif /* NUM_HEATERS > 0 */ // M190- power on case 190: diff --git a/heater.c b/heater.c index 259662c..68c6798 100644 --- a/heater.c +++ b/heater.c @@ -47,8 +47,18 @@ typedef struct { EE_factor EEMEM EE_factors[NUM_HEATERS]; void heater_init() { - // read factors from eeprom + #if NUM_HEATERS > 0 uint8_t i; + // setup pins + for (i = 0; i < NUM_HEATERS; i++) { + *(heaters[i].heater_port) &= ~heaters[i].heater_pin; + // DDR is always 1 address below PORT. ugly code but saves ram and an extra field in heaters[] which will never be used anywhere but here + *((volatile uint8_t *) (heaters[i].heater_port - 1)) |= heaters[i].heater_pin; + if (heaters[i].heater_pwm) + *heaters[i].heater_pwm = 0; + } + + // read factors from eeprom for (i = 0; i < NUM_HEATERS; i++) { heaters_pid[i].p_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_p_factor); heaters_pid[i].i_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_i_factor); @@ -62,6 +72,7 @@ void heater_init() { heaters_pid[i].i_limit = DEFAULT_I_LIMIT; } } + #endif } void heater_save_settings() { @@ -121,6 +132,7 @@ void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp) { } void heater_set(uint8_t index, uint8_t value) { + #if NUM_HEATERS > 0 if (heaters[index].heater_pwm) { *heaters[index].heater_pwm = value; } @@ -130,6 +142,7 @@ void heater_set(uint8_t index, uint8_t value) { else *heaters[index].heater_port &= ~MASK(heaters[index].heater_pin); } + #endif } void pid_set_p(uint8_t index, int32_t p) { diff --git a/intercom.c b/intercom.c new file mode 120000 index 0000000..a627b1f --- /dev/null +++ b/intercom.c @@ -0,0 +1 @@ +extruder/intercom.c \ No newline at end of file diff --git a/intercom.h b/intercom.h new file mode 120000 index 0000000..c515963 --- /dev/null +++ b/intercom.h @@ -0,0 +1 @@ +extruder/intercom.h \ No newline at end of file diff --git a/mendel.c b/mendel.c index 08fb037..aae3f35 100644 --- a/mendel.c +++ b/mendel.c @@ -46,28 +46,18 @@ void io_init(void) { WRITE(E_STEP_PIN, 0); SET_OUTPUT(E_STEP_PIN); WRITE(E_DIR_PIN, 0); SET_OUTPUT(E_DIR_PIN); - #ifdef HEATER_PIN - WRITE(HEATER_PIN, 0); SET_OUTPUT(HEATER_PIN); - #endif + // setup PWM timer: fast PWM, no prescaler + TCCR0A = MASK(WGM01) | MASK(WGM00); + TCCR0B = MASK(CS00); + TIMSK0 = 0; + OCR0A = 0; + OCR0B = 255; - #ifdef FAN_PIN - WRITE(FAN_PIN, 0); SET_OUTPUT(FAN_PIN); - #endif - - #if defined(HEATER_PWM) || defined(FAN_PWM) - // setup PWM timer: fast PWM, no prescaler - TCCR0A = MASK(WGM01) | MASK(WGM00); - TCCR0B = MASK(CS00); - TIMSK0 = 0; - OCR0A = 0; - OCR0B = 255; - - TCCR2A = MASK(WGM21) | MASK(WGM20); - TCCR2B = MASK(CS20); - TIMSK2 = 0; - OCR2A = 0; - OCR2B = 0; - #endif + TCCR2A = MASK(WGM21) | MASK(WGM20); + TCCR2B = MASK(CS20); + TIMSK2 = 0; + OCR2A = 0; + OCR2B = 0; #ifdef STEPPER_ENABLE_PIN power_off(); @@ -102,7 +92,10 @@ void init(void) { // start up analog read interrupt loop, if anything uses analog as determined by ANALOG_MASK in your config.h analog_init(); - + + // set up temperature inputs + temp_init(); + // enable interrupts sei(); @@ -114,12 +107,14 @@ void init(void) { } -void clock_250ms(void) { +void clock_10ms(void) { // reset watchdog wd_reset(); - + temp_tick(); +} +void clock_250ms(void) { if (steptimeout > (30 * 4)) { power_off(); } @@ -156,6 +151,10 @@ int main (void) gcode_parse_char(c); } + ifclock(CLOCK_FLAG_10MS) { + clock_10ms(); + } + ifclock(CLOCK_FLAG_250MS) { clock_250ms(); } diff --git a/temp.c b/temp.c index a662304..e587a39 100644 --- a/temp.c +++ b/temp.c @@ -9,11 +9,17 @@ #include "debug.h" #include "sersendf.h" #include "heater.h" +#ifdef GEN3 + #include "intercom.h" +#endif typedef enum { TT_THERMISTOR, TT_MAX6675, TT_AD595 +#ifdef GEN3 + , TT_INTERCOM +#endif } temp_types; typedef enum { @@ -71,6 +77,38 @@ uint16_t temptable[NUMTEMPS][2] PROGMEM = { #include "analog.h" #endif +void temp_init() { + uint8_t i; + for (i = 0; i < NUM_TEMP_SENSORS; i++) { + switch(temp_sensors[i].temp_type) { + #ifdef TEMP_MAX6675 + // initialised when read +/* case TT_MAX6675: + break;*/ + #endif + + #ifdef TEMP_THERMISTOR + // handled by analog_init() +/* case TT_THERMISTOR: + break;*/ + #endif + + #ifdef TEMP_AD595 + // handled by analog_init() +/* case TT_AD595: + break;*/ + #endif + + #ifdef GEN3 + case TT_INTERCOM: + intercom_init(); + update_send_cmd(0); + break; + #endif + } + } +} + void temp_sensor_tick() { uint8_t i = 0, all_within_range = 1; for (; i < NUM_TEMP_SENSORS; i++) { @@ -87,9 +125,9 @@ void temp_sensor_tick() { #ifdef TEMP_MAX6675 case TT_MAX6675: #ifdef PRR - PRR &= ~MASK(PRSPI); + PRR &= ~MASK(PRSPI); #elif defined PRR0 - PRR0 &= ~MASK(PRSPI); + PRR0 &= ~MASK(PRSPI); #endif SPCR = MASK(MSTR) | MASK(SPE) | MASK(SPR0); @@ -127,7 +165,7 @@ void temp_sensor_tick() { } } - // FIXME: placeholder number + // this number depends on how frequently temp_sensor_tick is called. the MAX6675 can give a reading every 0.22s, so set this to about 250ms temp_sensors_runtime[i].next_read_time = 25; break; @@ -152,7 +190,6 @@ void temp_sensor_tick() { if (j == NUMTEMPS) temp = temptable[NUMTEMPS-1][1]; - // FIXME: placeholder number temp_sensors_runtime[i].next_read_time = 0; break; @@ -166,11 +203,21 @@ void temp_sensor_tick() { // >>8 instead of >>10 because internal temp is stored as 14.2 fixed point temp = (temp * 500L) >> 8; - // FIXME: placeholder number - temp_sensors[i].next_read_time = 0; + temp_sensors_runtime[i].next_read_time = 0; break; #endif /* TEMP_AD595 */ + + #ifdef GEN3 + case TT_INTERCOM: + temp = get_read_cmd() << 2; + + start_send(); + + temp_sensors_runtime[i].next_read_time = 0; + + break; + #endif /* GEN3 */ } temp_sensors_runtime[i].last_read_temp = temp; @@ -202,6 +249,10 @@ uint8_t temp_achieved() { void temp_set(uint8_t index, uint16_t temperature) { temp_sensors_runtime[index].target_temp = temperature; temp_sensors_runtime[index].temp_residency = 0; +#ifdef GEN3 + if (temp_sensors[index].temp_type == TT_INTERCOM) + update_send_cmd(temperature >> 2); +#endif } void temp_print(uint8_t index) { diff --git a/temp.h b/temp.h index 5555b8e..c912760 100644 --- a/temp.h +++ b/temp.h @@ -13,6 +13,8 @@ we still need to specify which analog pins we use in machine.h for the analog se #define temp_tick temp_sensor_tick +void temp_init(void); + void temp_sensor_tick(void); uint8_t temp_achieved(void); diff --git a/timer.c b/timer.c index 2f4586f..ddd5e60 100644 --- a/timer.c +++ b/timer.c @@ -6,6 +6,7 @@ volatile uint32_t next_step_time; +uint8_t clock_counter_10ms = 0; uint8_t clock_counter_250ms = 0; uint8_t clock_counter_1s = 0; volatile uint8_t clock_flag = 0; @@ -30,14 +31,21 @@ ISR(TIMER1_CAPT_vect) { /* clock stuff */ - clock_counter_250ms += (TICK_TIME / (F_CPU / 1000)); - if (clock_counter_250ms >= 250) { - clock_counter_250ms -= 250; - clock_flag |= CLOCK_FLAG_250MS; - clock_counter_1s += 1; - if (clock_counter_1s >= 4) { - clock_counter_1s -= 4; - clock_flag |= CLOCK_FLAG_1S; + clock_counter_10ms += (TICK_TIME / (F_CPU / 1000)); + if (clock_counter_10ms >= 10) { + clock_counter_10ms -= 10; + clock_flag |= CLOCK_FLAG_10MS; + + clock_counter_250ms += 10; + if (clock_counter_250ms >= 250) { + clock_counter_250ms -= 250; + clock_flag |= CLOCK_FLAG_250MS; + + clock_counter_1s += 1; + if (clock_counter_1s >= 4) { + clock_counter_1s -= 4; + clock_flag |= CLOCK_FLAG_1S; + } } } } diff --git a/timer.h b/timer.h index 2626860..dd6b6be 100644 --- a/timer.h +++ b/timer.h @@ -13,8 +13,9 @@ clock stuff */ extern volatile uint8_t clock_flag; -#define CLOCK_FLAG_250MS 1 -#define CLOCK_FLAG_1S 2 +#define CLOCK_FLAG_10MS 1 +#define CLOCK_FLAG_250MS 2 +#define CLOCK_FLAG_1S 4 #define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F)) /*