diff --git a/.gitignore b/.gitignore index 76c1d3e..22c8ce7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ temporal.png temporal_data +config.h sim diff --git a/Makefile b/Makefile index e7f474d..50565c2 100644 --- a/Makefile +++ b/Makefile @@ -87,7 +87,7 @@ PROGBAUD = 57600 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 intercom.c pinio.c clock.c +SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c timer.c sermsg.c dda_queue.c debug.c sersendf.c delay.c pinio.c clock.c watchdog.c ARCH = avr- CC = $(ARCH)gcc @@ -104,7 +104,7 @@ OBJ = $(patsubst %.c,%.o,${SOURCES}) .PHONY: all program clean size .PRECIOUS: %.o %.elf -all: config.h $(PROGRAM).hex $(PROGRAM).lst $(PROGRAM).sym size +all: config.h $(PROGRAM).hex $(PROGRAM).lst program: $(PROGRAM).hex config.h stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT) diff --git a/README b/README index 0a98527..d27534a 100644 --- a/README +++ b/README @@ -1,35 +1,33 @@ -A modified rewrite of the Reprap Mendel firmware for use with CNC machines. - -This code has merely been modified - all the work has been done by the legendary Triffid_Hunter, Traumflug and jakepoz ;) - -Eventually, if there is a need, some sort of a 'suite' could be put together, to allow the individual to select the components that they have, ie. -X axis, Y axis, Z axis, extruder, heater, fan, thermistor, spindle, end stops, lcd displays -and have the code build for their platform without all the unnessecary routines (if you have no extruder, you do not need PID). - -For now, I am concentrating on getting the basic CNC thing down :) - -/############################################################################\ -# Capabilities # -\############################################################################/ +Rewrite of Reprap Mendel firmware: * 100% integer computations * serial transmit buffer +* can fit onto atmega168 depending on selected options +* works on atmega328p * works on atmega644p +* porting to atmega1280 in progress * will work on larger atmegas with minor porting -/############################################################################\ +############################################################################## +# # # How to use # -\############################################################################/ - -) check programming settings in Makefile -) make -) make program -a) if programming blank chip, make program-fuses -) have a play - -/############################################################################\ +# # +############################################################################## + +1) COPY config.h.dist to config.h and edit to suit your electronics +2) check programming settings in Makefile +3) make +4) make program +4a) if programming blank chip, make program-fuses +5) ./sender.sh +6) have a play, go to 1) if not right +7) try printing something! + +############################################################################## +# # # Requirements # -\############################################################################/ +# # +############################################################################## Compile: gnu make @@ -39,9 +37,11 @@ Program: avrdude something that avrdude supports: bootloader, separate programmer, whatever -/############################################################################\ +############################################################################## +# # # License # -\############################################################################/ +# # +############################################################################## This firmware is Copyright (C) 2009-2010 Michael Moon aka Triffid_Hunter @@ -59,9 +59,11 @@ 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 -/############################################################################\ +############################################################################## +# # # Rationale and History # -\############################################################################/ +# # +############################################################################## I started building my electronics with only a regular arduino to test with. This was perfectly sufficient for playing with the pololu stepper controllers and the max6675 I bought after reading about all the issues with thermistors that people were having. After a while I decided to check out the official firmware but it required an atmega644. I wondered why. @@ -82,9 +84,11 @@ Cefiar posted me some thermistors to sponsor addition of thermistor-reading code Many others have given encouragement and suggestions without which this firmware may never be what it is today. -/############################################################################\ +############################################################################## +# # # Architectural Overview # -\############################################################################/ +# # +############################################################################## FiveD on Arduino is quite similar to the official firmware in some ways, and markedly different in others. FiveD on Arduino has as much modularity as I could get away with without sacrificing efficiency. @@ -94,9 +98,11 @@ At startup, the code in mendel.c is run first. This initialises all the modules It is necessary to keep interrupts very short on small microcontrollers, and I have endeavoured to keep them all as short as possible. Unfortunately, dda_step[dda.c] is fairly large. I simply hope that it doesn't take so much time that it interferes with the other interrupts too much. -/############################################################################\ +############################################################################## +# # # Interesting code sections # -\############################################################################/ +# # +############################################################################## The serial ringbuffers are critical for good communication, but for some reason the official arduino libraries don't implement a tx queue, all but preventing sending stuff from interrupt context. As long as the queues have a length of 2^n, we can use bitwise operations rather than numerical comparison to trim the read and write pointers. The serial send function (serial_writechar[serial.c]) is necessarily careful about checking if it's in an interrupt and only waiting for space in the queue if it's not. The dda queue is also a ringbuffer, although its implementation is harder to see as it's embedded in lots of other stuff. @@ -107,17 +113,24 @@ The fixed-point stuff is fun, although we have to manually ensure that the decim The PID code in heater.c is probably quite generalisable, and seems to work well when tuned. Google knows of plenty of PID tuning guides. -/############################################################################\ +############################################################################## +# # # Resources # -\############################################################################/ +# # +############################################################################## Forum thread: http://forums.reprap.org/read.php?147,33082 Source Repository: http://github.com/triffid/FiveD_on_Arduino Wiki Page: http://objects.reprap.org/wiki/FiveD_on_Arduino -/############################################################################\ +############################################################################## +# # # File descriptions # -\############################################################################/ +# # +############################################################################## + +*** analog.[ch] +This is the analog subsystem. Only used if you have a thermistor or ad595 *** arduino.h, arduino_[chip].h Pin mappings and helper functions for various atmegas @@ -128,6 +141,9 @@ Regular functions that run in main loop rather than an interrupt *** config.h.dist, config.h Configuration for your electronics and hardware. Copy config.h.dist to config.h, edit config.h to suit +*** copier.[ch] +A totally untested and currently unused chunk of code for copying firmware to another identical chip + *** dda.[ch] A rather complex block of math that figures out when to step each axis according to speed and acceleration profiles and received moves @@ -140,12 +156,24 @@ Debugging aids *** delay.[ch] Delay functions +*** FiveD_on_Arduino.pde +Allows firmware to be built in arduino ide + +*** func.sh +Lots of host-side shell scripts for talking to firmware + *** gcode_parse.[ch] Gcode parser. Scaling of factors to internally used integer or fixed point happens here too. *** gcode_process.[ch] Gcodes actually get executed here after being parsed. +*** heater.[ch] +Heater management, including PID and PWM algorithms, and some configuration parameters + +*** intercom.[ch] +Gen3 serial link control and communication + *** LICENSE Gnu GPL2 license @@ -173,5 +201,12 @@ Functions for sending messages and values to host *** sersendf.[ch] A small, crude printf implementation +*** temp.[ch] +Temperature sensor management, includes some configuration parameters + *** timer.[ch] -Timer management, used primarily by dda.c for timing steps \ No newline at end of file +Timer management, used primarily by dda.c for timing steps + +*** watchdog.[ch] +Watchdog management. resets chip if firmware locks up or does something strange + diff --git a/clock.c b/clock.c index c6ef12a..12be710 100644 --- a/clock.c +++ b/clock.c @@ -5,6 +5,7 @@ #include "dda_queue.h" #include "timer.h" #include "debug.h" +#include "watchdog.h" void clock_250ms() { if (steptimeout > (30 * 4)) { diff --git a/config.h.dist b/config.h.dist new file mode 100644 index 0000000..f58be5f --- /dev/null +++ b/config.h.dist @@ -0,0 +1,255 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +/* + CONTENTS + + 1. Mechanical/Hardware + 2. Acceleration settings + 3. Pinouts + 4. Temperature sensors + 5. Heaters + 6. Communication options + 7. Miscellaneous +*/ + +/***************************************************************************\ +* 1. MECHANICAL/HARDWARE * * +\***************************************************************************/ + +/* + Microcontroller type is set to atmega644p in the Makefile. +*/ + +/* + CPU clock rate +*/ +#ifndef F_CPU + #define F_CPU 20000000L +#endif + +#define HOST + +/* + Values reflecting the gearing of your machine. + All numbers are fixed point integers, so no more than 3 digits to the right of the decimal point, please :-) +*/ + +// calculate these values appropriate for your machine +// for threaded rods, this is (steps motor per turn) / (pitch of the thread) +// for belts, this is (steps per motor turn) / (number of gear teeth) / (belt module) +// half-stepping doubles the number, quarter stepping requires * 4, etc. +#define STEPS_PER_MM_X 320.000 +#define STEPS_PER_MM_Y 320.000 +#define STEPS_PER_MM_Z 320.000 + +/* + Values depending on the capabilities of your stepper motors and other mechanics. + All numbers are integers, no decimals allowed. + + Units are mm/min +*/ + +// used for G0 rapid moves and as a cap for all other feedrates +#define MAXIMUM_FEEDRATE_X 200 +#define MAXIMUM_FEEDRATE_Y 200 +#define MAXIMUM_FEEDRATE_Z 100 + +// used when searching endstops and as default feedrate +#define SEARCH_FEEDRATE_X 50 +#define SEARCH_FEEDRATE_Y 50 +#define SEARCH_FEEDRATE_Z 50 + +/***************************************************************************\ +* 2. ACCELERATION * +* IMPORTANT: choose only one! These algorithms choose when to step, trying * +* to use more than one will have undefined and probably * +* disastrous results! * +\***************************************************************************/ + +/* + acceleration, reprap style. + 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. +*/ +// #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 +*/ +#define ACCELERATION_RAMPING + +// how fast to accelerate when using ACCELERATION_RAMPING +// smaller values give quicker acceleration +// valid range = 1 to 8,000,000; 500,000 is a good starting point +#define ACCELERATION_STEEPNESS 500000 + + +/* + temporal step algorithm + This algorithm causes the timer to fire when any axis needs to step, instead of synchronising to the axis with the most steps ala bresenham. + + This algorithm is not a type of acceleration, and I haven't worked out how to integrate acceleration with it. + However it does control step timing, so acceleration algorithms seemed appropriate + + The Bresenham algorithm is great for drawing lines, but not so good for steppers - In the case where X steps 3 times to Y's two, Y experiences massive jitter as it steps in sync with X every 2 out of 3 X steps. This is a worst-case, but the problem exists for most non-45/90 degree moves. At higher speeds, the jitter /will/ cause position loss and unnecessary vibration. + This algorithm instead calculates when a step occurs on any axis, and sets the timer to that value. + + // TODO: figure out how to add acceleration to this algorithm +*/ +// #define ACCELERATION_TEMPORAL + + + +/***************************************************************************\ +* 3. PINOUTS * +\***************************************************************************/ + +/* + Machine Pin Definitions + - make sure to avoid duplicate usage of a pin + - comment out pins not in use, as this drops the corresponding code and makes operations faster +*/ + +#include "arduino.h" + +#ifndef GEN3 + /* + user defined pins + adjust to suit your electronics + */ + + #define X_STEP_PIN DIO21 //XSTEP is PC5... ie. DIO21 + #define X_DIR_PIN DIO18 //XDIR pin is PC2. DIO18 + #define X_MIN_PIN DIO0 // XMIN is not correct, we have an XHOME on PB0 + + #define Y_STEP_PIN DIO22 // PC6 is DIO22 + #define Y_DIR_PIN DIO17 // DIO17 is PC1 + #define Y_MIN_PIN DIO1 // PB1 + + #define Z_STEP_PIN DIO23 // PC7 is DIO23 + #define Z_DIR_PIN DIO16 // DIO16 is PC0 + #define Z_MIN_PIN DIO7 // PB2 + + #define STEPPER_ENABLE_PIN DIO19 // PC3 (active low) + #define STEPPER_RESET_PIN DIO20 // PC4 (needs to be high to move) + + +#else + /* + this is the official gen3 reprap motherboard pinout + */ + #define TX_ENABLE_PIN DIO12 + #define RX_ENABLE_PIN DIO13 + + #define X_STEP_PIN DIO15 + #define X_DIR_PIN DIO18 + #define X_MIN_PIN DIO20 + #define X_MAX_PIN DIO21 + #define X_ENABLE_PIN DIO19 + + #define Y_STEP_PIN DIO23 + #define Y_DIR_PIN DIO22 + #define Y_MIN_PIN AIO6 + #define Y_MAX_PIN AIO5 + #define Y_ENABLE_PIN DIO7 + + #define Z_STEP_PIN AIO4 + #define Z_DIR_PIN AIO3 + #define Z_MIN_PIN AIO1 + #define Z_MAX_PIN AIO0 + #define Z_ENABLE_PIN AIO2 + + #define E_STEP_PIN DIO16 + #define E_DIR_PIN DIO17 + + #define SD_CARD_DETECT DIO2 + #define SD_WRITE_PROTECT DIO3 +#endif + +/***************************************************************************\ +* 5. TEMPERATURE SENSORS * +\***************************************************************************/ + +// how many temperature sensors do you have? +#define NUM_TEMP_SENSORS 0 + +/***************************************************************************\ +* 5. HEATERS * +\***************************************************************************/ + +// number of heaters- for GEN3, set to zero as extruder manages the heater by itself +#define NUM_HEATERS 0 + +/***************************************************************************\ +* 6. COMMUNICATION OPTIONS * +\***************************************************************************/ + +/* + RepRap Host changes it's communications protocol from time to time and intentionally avoids backwards compatibility. Set this to the date the source code of your Host was fetched from RepRap's repository, which is likely also the build date. + See the discussion on the reprap-dev mailing list from 11 Oct. 2010. + + Undefine it for best human readability, set it to an old date for compatibility with hosts before August 2010 +*/ +// #define REPRAP_HOST_COMPATIBILITY 19750101 +#define REPRAP_HOST_COMPATIBILITY 20100806 +// #define REPRAP_HOST_COMPATIBILITY + +/* + Xon/Xoff flow control. + Redundant when using RepRap Host for sending GCode, but mandatory when sending GCode files with a plain terminal emulator, like GtkTerm (Linux), CoolTerm (Mac) or HyperTerminal (Windows). + Can also be set in Makefile +*/ +#define XONXOFF + + + +/***************************************************************************\ +* 7. MISCELLANEOUS OPTIONS * +\***************************************************************************/ + +/* + DEBUG + enables /heaps/ of extra output, and some extra M-codes. + WARNING: this WILL break most host-side talkers that expect particular responses from firmware such as reprap host and replicatorG + use with serial terminal or other suitable talker only. +*/ +// #define DEBUG + +/* + move buffer size, in number of moves + 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 so a longer buffer allows more of the math to be done during preceding longer moves +*/ +#define MOVEBUFFER_SIZE 8 + + +/* + FiveD on Arduino implements a watchdog, which has to be reset every 250ms or it will reboot the controller. As rebooting (and letting the GCode sending application trying to continue the build with a then different Home point) is probably even worse than just hanging, and there is no better restore code in place, this is disabled for now. +*/ +// #define USE_WATCHDOG + +/* + analog subsystem stuff + REFERENCE - which analog reference to use. see analog.h for choices +*/ +#define REFERENCE REFERENCE_AVCC + +/* + this option makes the step interrupt interruptible (nested). + this should help immensely with dropped serial characters, but may also make debugging infuriating due to the complexities arising from nested interrupts +*/ +#define STEP_INTERRUPT_INTERRUPTIBLE 1 + +/* + how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535) +*/ +#define TICK_TIME 2 MS +#define TICK_TIME_MS (TICK_TIME / (F_CPU / 1000)) + + +// this is the scaling of internally stored PID values. 1024L is a good value +#define PID_SCALE 1024L + +#endif /* _CONFIG_H */ diff --git a/dda.c b/dda.c index 48046e4..786cff9 100644 --- a/dda.c +++ b/dda.c @@ -132,7 +132,7 @@ void dda_create(DDA *dda, TARGET *target) { dda->z_direction = (target->Z >= startpoint.Z)?1:0; if (debug_flags & DEBUG_DDA) - sersendf_P(PSTR("%ld,%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z, target->E - startpoint.E); + sersendf_P(PSTR("%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z); dda->total_steps = dda->x_delta; if (dda->y_delta > dda->total_steps) diff --git a/dda_queue.c b/dda_queue.c index ddc9d2f..b13cabc 100644 --- a/dda_queue.c +++ b/dda_queue.c @@ -30,12 +30,8 @@ uint8_t queue_empty() { void queue_step() { // do our next step if (movebuffer[mb_tail].live) { - if (movebuffer[mb_tail].waitfor_temp) { setTimer(movebuffer[mb_tail].c >> 8); - if (temp_achieved()) { - movebuffer[mb_tail].live = movebuffer[mb_tail].waitfor_temp = 0; - serial_writestr_P(PSTR("Temp achieved\n")); - } + movebuffer[mb_tail].live = 0; #if STEP_INTERRUPT_INTERRUPTIBLE sei(); @@ -45,7 +41,7 @@ void queue_step() { // NOTE: dda_step makes this interrupt interruptible after steps have been sent but before new speed is calculated. dda_step(&(movebuffer[mb_tail])); } - } + // fall directly into dda_start instead of waiting for another step // the dda dies not directly after its last step, but when the timer fires and there's no steps to do diff --git a/gcode_process.c b/gcode_process.c index a0d101c..9469bda 100644 --- a/gcode_process.c +++ b/gcode_process.c @@ -13,6 +13,7 @@ #include "pinio.h" #include "debug.h" #include "clock.h" +#include "watchdog.h" // the current tool uint8_t tool; diff --git a/mendel.c b/mendel.c index a7e54cd..baf07a3 100644 --- a/mendel.c +++ b/mendel.c @@ -16,6 +16,7 @@ #include "pinio.h" #include "arduino.h" #include "clock.h" +#include "watchdog.h" void io_init(void) { // disable modules we don't use @@ -60,9 +61,6 @@ void io_init(void) { #ifdef Z_ENABLE_PIN WRITE(Z_ENABLE_PIN, 1); SET_OUTPUT(Z_ENABLE_PIN); #endif - - WRITE(E_STEP_PIN, 0); SET_OUTPUT(E_STEP_PIN); - WRITE(E_DIR_PIN, 0); SET_OUTPUT(E_DIR_PIN); // setup PWM timers: fast PWM, no prescaler TCCR0A = MASK(WGM01) | MASK(WGM00); diff --git a/pinio.h b/pinio.h index 9af3def..1c58de2 100644 --- a/pinio.h +++ b/pinio.h @@ -40,10 +40,6 @@ #define Z_INVERT_ENABLE 0 #endif -#ifndef E_INVERT_DIR - #define E_INVERT_DIR 0 -#endif - #ifndef STEPPER_ENABLE_INVERT #define STEPPER_ENABLE_INVERT 0 #endif @@ -109,11 +105,7 @@ End Step - All Steppers (so we don't have to delay in interrupt context) */ -#ifndef DC_EXTRUDER - #define unstep() do { _x_step(0); _y_step(0); _z_step(0); _e_step(0); } while (0) -#else #define unstep() do { _x_step(0); _y_step(0); _z_step(0); } while (0) -#endif /* Stepper Enable Pins diff --git a/watchdog.c b/watchdog.c new file mode 100644 index 0000000..621280b --- /dev/null +++ b/watchdog.c @@ -0,0 +1,46 @@ +#include "watchdog.h" + +#ifdef USE_WATCHDOG + +#include +#include + +#include "arduino.h" +#include "serial.h" + +volatile uint8_t wd_flag = 0; + +// uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); +// void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3"))); +// void get_mcusr(void) { +// mcusr_mirror = MCUSR; +// MCUSR = 0; +// wdt_disable(); +// } + +ISR(WDT_vect) { +// watchdog has tripped- no main loop activity for 0.5s, probably a bad thing +// if watchdog fires again, we will reset +// perhaps we should do something more intelligent in this interrupt? +wd_flag |= 1; +} + +void wd_init() { +// check if we were reset by the watchdog +// if (mcusr_mirror & MASK(WDRF)) +// serial_writestr_P(PSTR("Watchdog Reset!\n")); + +// 0.25s timeout, interrupt and system reset +wdt_enable(WDTO_500MS); +WDTCSR |= MASK(WDIE); +} + +void wd_reset() { +wdt_reset(); +if (wd_flag) { +WDTCSR |= MASK(WDIE); +wd_flag &= ~1; +} +} + +#endif /* USE_WATCHDOG */ \ No newline at end of file diff --git a/watchdog.h b/watchdog.h new file mode 100644 index 0000000..8881aa2 --- /dev/null +++ b/watchdog.h @@ -0,0 +1,22 @@ +#ifndef _WATCHDOG_H +#define _WATCHDOG_H + +#include "config.h" + +#ifdef USE_WATCHDOG + +// initialize +void wd_init(void) __attribute__ ((cold)); + +// reset timeout- must be called periodically or we reboot +void wd_reset(void); + +// notable lack of disable function + +#else /* USE_WATCHDOG */ + +#define wd_init() /* empty */ +#define wd_reset() /* empty */ + +#endif /* USE_WATCHDOG */ +#endif /* _WATCHDOG_H */ \ No newline at end of file