Massive Doxygen documentation addition

'make doc' then point your browser at doc/html/

Needs plenty of cleanup and polishing, but the main bulk is here

even documents your configuration! ;)
This commit is contained in:
Michael Moon 2011-03-22 01:34:36 +11:00
parent b03dd87665
commit 0dc7d77885
42 changed files with 2875 additions and 549 deletions

2
.gitignore vendored
View File

@ -18,4 +18,4 @@ temporal_data
config.h
ThermistorTable.h
sim
doc

1657
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -178,6 +178,9 @@ config.h: config.h.dist
@diff -bBEuF '^. [[:digit:]]. [[:upper:]]' config.h config.h.dist
@false
doc: Doxyfile *.c *.h
doxygen $<
%.o: %.c config.h Makefile
@echo " CC $@"
@$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $(subst .o,.c,$@)

View File

@ -1,10 +1,16 @@
#include "analog.h"
/** \file
\brief Analog subsystem
*/
#include "temp.h"
#include <avr/interrupt.h>
/* OR-combined mask of all channels */
#undef DEFINE_TEMP_SENSOR
//! automagically generate analog_mask from DEFINE_TEMP_SENSOR entries in config.h
#define DEFINE_TEMP_SENSOR(name, type, pin) | (((type == TT_THERMISTOR) || (type == TT_AD595)) ? 1 << (pin) : 0)
static const uint8_t analog_mask = 0
#include "config.h"
@ -14,6 +20,7 @@ static const uint8_t analog_mask = 0
static uint8_t adc_counter;
static volatile uint16_t adc_result[8] __attribute__ ((__section__ (".bss")));
//! Configure all registers, start interrupt loop
void analog_init() {
if (analog_mask > 0) {
#ifdef PRR
@ -36,6 +43,10 @@ void analog_init() {
} /* analog_mask > 0 */
}
/*! Analog Interrupt
This is where we read our analog value and store it in an array for later retrieval
*/
ISR(ADC_vect, ISR_NOBLOCK) {
// emulate free-running mode but be more deterministic about exactly which result we have, since this project has long-running interrupts
if (analog_mask > 0) {
@ -52,6 +63,10 @@ ISR(ADC_vect, ISR_NOBLOCK) {
}
}
/*! Read analog value from saved result array
\param channel Channel to be read
\return analog reading, 10-bit right aligned
*/
uint16_t analog_read(uint8_t channel) {
if (analog_mask > 0) {
uint16_t r;

View File

@ -26,6 +26,7 @@
#endif
void analog_init(void);
uint16_t analog_read(uint8_t channel);
#endif /* _ANALOG_H */

View File

@ -1,3 +1,10 @@
/*!
\file
\brief pin definitions and I/O macros
why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
#ifndef _ARDUINO_H
#define _ARDUINO_H
@ -8,7 +15,8 @@
*/
#ifndef MASK
#define MASK(PIN) (1 << PIN)
/// MASKING- returns \f$2^PIN\f$
#define MASK(PIN) (1 << PIN)
#endif
/*
@ -17,26 +25,40 @@
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
*/
/// Read a pin
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
/// write to a pin
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
/// toggle a pin
#define _TOGGLE(IO) do { IO ## _RPORT = MASK(IO ## _PIN); } while (0)
/// set pin as input
#define _SET_INPUT(IO) do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
/// set pin as output
#define _SET_OUTPUT(IO) do { IO ## _DDR |= MASK(IO ## _PIN); } while (0)
/// check if pin is an input
#define _GET_INPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) == 0)
/// check if pin is an output
#define _GET_OUTPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) != 0)
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
/// Read a pin wrapper
#define READ(IO) _READ(IO)
/// Write to a pin wrapper
#define WRITE(IO, v) _WRITE(IO, v)
/// toggle a pin wrapper
#define TOGGLE(IO) _TOGGLE(IO)
/// set pin as input wrapper
#define SET_INPUT(IO) _SET_INPUT(IO)
/// set pin as output wrapper
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
/// check if pin is an input wrapper
#define GET_INPUT(IO) _GET_INPUT(IO)
/// check if pin is an output wrapper
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
/*

12
clock.c
View File

@ -1,5 +1,9 @@
#include "clock.h"
/** \file
\brief Do stuff periodically
*/
#include "pinio.h"
#include "sersendf.h"
#include "dda_queue.h"
@ -10,6 +14,10 @@
#include "heater.h"
#include "serial.h"
/*! do stuff every 1/4 second
called from clock_10ms(), do not call directly
*/
void clock_250ms() {
if (steptimeout > (30 * 4)) {
power_off();
@ -40,6 +48,10 @@ void clock_250ms() {
#endif
}
/*! do stuff every 10 milliseconds
call from ifclock(CLOCK_FLAG_10MS) in busy loops
*/
void clock_10ms() {
// reset watchdog
wd_reset();

View File

@ -1,5 +1,8 @@
/* Notice to developers: this file is intentionally included twice. */
/** \file
\brief Gen3 Electronics Sample Configuration
*/
/*
CONTENTS
@ -30,14 +33,14 @@
#error GEN3 has a 644P/644PA! set your cpu type in Makefile!
#endif
/*
/** \def F_CPU
CPU clock rate
*/
#ifndef F_CPU
#define F_CPU 16000000L
#endif
/*
/** \def HOST
This is the motherboard, as opposed to the extruder. See extruder/ directory for GEN3 extruder firmware
*/
#define HOST
@ -45,17 +48,17 @@
/*
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.
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 200.000
// http://blog.arcol.hu/?p=157 may help with this next one
/// http://blog.arcol.hu/?p=157 may help with this one
#define STEPS_PER_MM_E 320.000
@ -66,25 +69,25 @@
Units are mm/min
*/
// used for G0 rapid moves and as a cap for all other feedrates
/// 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
#define MAXIMUM_FEEDRATE_E 200
// used when searching endstops and as default feedrate
/// used when searching endstops and as default feedrate
#define SEARCH_FEEDRATE_X 50
#define SEARCH_FEEDRATE_Y 50
#define SEARCH_FEEDRATE_Z 50
#define SEARCH_FEEDRATE_E 50
// this is how many steps to suck back the filament by when we stop. set to zero to disable
/// this is how many steps to suck back the filament by when we stop. set to zero to disable
#define E_STARTSTOP_STEPS 20
/*
Soft axis limits, in mm
undefine if you don't want to use them
/**
Soft axis limits, in mm
undefine if you don't want to use them
*/
#define X_MIN 0.0
@ -108,25 +111,25 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/** \def ACCELERATION_REPRAP
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
/*
/** \def ACCELERATION_RAMPING
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
/// 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
/*
/** \def ACCELERATION_TEMPORAL
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.
@ -136,7 +139,7 @@ undefine if you don't want to use them
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
\todo figure out how to add acceleration to this algorithm
*/
// #define ACCELERATION_TEMPORAL
@ -148,7 +151,7 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/**
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
@ -156,13 +159,13 @@ undefine if you don't want to use them
#include "arduino.h"
/*
/** \def USE_INTERNAL_PULLUPS
internal pullup resistors
the ATmega has internal pullup resistors on it's input pins which are counterproductive with the commonly used eletronic endstops, so they should be switched off. For other endstops, like mechanical ones, you may want to uncomment this.
*/
//#define USE_INTERNAL_PULLUPS
/*
/**
this is the official gen3 reprap motherboard pinout
*/
#define TX_ENABLE_PIN DIO12
@ -214,15 +217,17 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/**
TEMP_HYSTERESIS: actual temperature must be target +/- hysteresis before target temperature can be achieved.
NOTE: format is 30.2 fixed point, so value of 20 actually means +/- 5 degrees
*/
#define TEMP_HYSTERESIS 20
/**
TEMP_RESIDENCY_TIME: actual temperature must be close to target for this long before target is achieved
temperature is "achieved" for purposes of M109 and friends when actual temperature is within [hysteresis] of target for [residency] seconds
*/
#define TEMP_HYSTERESIS 20
#define TEMP_RESIDENCY_TIME 60
// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
@ -259,15 +264,17 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
* *
\***************************************************************************/
// check if heater responds to changes in target temperature, disable and spit errors if not
// largely untested, please comment in forum if this works, or doesn't work for you!
/** \def HEATER_SANITY_CHECK
check if heater responds to changes in target temperature, disable and spit errors if not
largely untested, please comment in forum if this works, or doesn't work for you!
*/
// #define HEATER_SANITY_CHECK
/***************************************************************************\
* *
* Define your heaters here *
* *
* WARNING: For GEN3, ONLY DEFINE HEATERS CONNECTED TO YOUR MOTHERBOARD HERE *
* \WARNING For GEN3, ONLY DEFINE HEATERS CONNECTED TO YOUR MOTHERBOARD HERE *
* Heaters connected to your extruder controller belong in extruder/config.h *
* *
* If your heater isn't on a PWM-able pin, set heater_pwm to zero and we'll *
@ -296,11 +303,15 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
// DEFINE_HEATER(chamber, PORTD, PIND7, OCR2A)
// DEFINE_HEATER(motor, PORTD, PIND6, OCR2B)
// and now because the c preprocessor isn't as smart as it could be,
// uncomment the ones you've listed above and comment the rest.
// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
/** \def HEATER_EXTRUDER
\def HEATER_BED
\def HEATER_FAN
and now because the c preprocessor isn't as smart as it could be,
uncomment the ones you've listed above and comment the rest.
\NOTE these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
*/
// #define HEATER_EXTRUDER HEATER_extruder
// #define HEATER_BED HEATER_bed
@ -314,7 +325,7 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
* *
\***************************************************************************/
/*
/** \def REPRAP_HOST_COMPATIBILITY
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.
@ -324,12 +335,12 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
#define REPRAP_HOST_COMPATIBILITY 20100806
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
/*
/**
Baud rate for the connection to the host. Usually 115200, other common values are 19200, 38400 or 57600.
*/
#define BAUD 115200
/*
/** \def XONXOFF
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
@ -344,7 +355,7 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
* *
\***************************************************************************/
/*
/** \def DEBUG
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
@ -352,12 +363,14 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
*/
// #define DEBUG
/*
/** \def BANG_BANG
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
*//** \def BANG_BANG_ON
BANG_BANG_ON
PWM value for 'on'
*//** \def BANG_BANG_OFF
BANG_BANG_OFF
PWM value for 'off'
*/
@ -365,44 +378,44 @@ DEFINE_TEMP_SENSOR(noheater, TT_INTERCOM, 0)
// #define BANG_BANG_ON 200
// #define BANG_BANG_OFF 45
/*
/**
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
/*
/** \def DC_EXTRUDER
DC extruder
If you have a DC motor extruder, configure it as a "heater" above and define this value as the index or name. You probably also want to comment out E_STEP_PIN and E_DIR_PIN in the Pinouts section above
*/
// #define DC_EXTRUDER HEATER_motor
// #define DC_EXTRUDER_PWM 180
/*
/** \def USE_WATCHDOG
Teacup 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
/*
/** \def STEP_INTERRUPT_INTERRUPTIBLE
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
/*
/**
temperature history count. This is how many temperature readings to keep in order to calculate derivative in PID loop
higher values make PID derivative term more stable at the expense of reaction time
*/
#define TH_COUNT 8
// this is the scaling of internally stored PID values. 1024L is a good value
/// this is the scaling of internally stored PID values. 1024L is a good value
#define PID_SCALE 1024L

View File

@ -1,7 +1,7 @@
/* Notice to developers: this file is intentionally included twice. */
/*
Sample configuration file for the GEN6-Board sold by Camiel Gubbels.
/** \file
\brief Sample configuration file for the GEN6-Board sold by Camiel Gubbels.
http://www.reprap.org/wiki/Generation_6_Electronics
*/
@ -33,14 +33,14 @@
#error GEN6 has a 644P! set your cpu type in Makefile!
#endif
/*
/** \def F_CPU
CPU clock rate
*/
#ifndef F_CPU
#define F_CPU 16000000L
#endif
/*
/** \def HOST
This is the motherboard, as opposed to the extruder. See extruder/ directory for GEN3 extruder firmware
*/
#define HOST
@ -58,7 +58,7 @@
#define STEPS_PER_MM_Y (320.000*8)
#define STEPS_PER_MM_Z (200.000*8)
// http://blog.arcol.hu/?p=157 may help with this next one
/// http://blog.arcol.hu/?p=157 may help with this one
#define STEPS_PER_MM_E (320.000*8)
@ -69,25 +69,25 @@
Units are mm/min
*/
// used for G0 rapid moves and as a cap for all other feedrates
/// 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
#define MAXIMUM_FEEDRATE_E 200
// used when searching endstops and as default feedrate
/// used when searching endstops and as default feedrate
#define SEARCH_FEEDRATE_X 50
#define SEARCH_FEEDRATE_Y 50
#define SEARCH_FEEDRATE_Z 50
#define SEARCH_FEEDRATE_E 50
// this is how many steps to suck back the filament by when we stop. set to zero to disable
/// this is how many steps to suck back the filament by when we stop. set to zero to disable
#define E_STARTSTOP_STEPS 20
/*
Soft axis limits, in mm
undefine if you don't want to use them
/**
Soft axis limits, in mm
undefine if you don't want to use them
*/
#define X_MIN 0.0
@ -111,24 +111,24 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/** \def ACCELERATION_REPRAP
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
/*
/** \def ACCELERATION_RAMPING
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
/// 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
/*
/** \def ACCELERATION_TEMPORAL
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.
@ -138,7 +138,7 @@ undefine if you don't want to use them
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
\TODO figure out how to add acceleration to this algorithm
*/
// #define ACCELERATION_TEMPORAL
@ -158,7 +158,7 @@ undefine if you don't want to use them
#include "arduino.h"
/*
/** \def USE_INTERNAL_PULLUPS
internal pullup resistors
the ATmega has internal pullup resistors on it's input pins which are counterproductive with the commonly used eletronic endstops, so they should be switched off. For other endstops, like mechanical ones, you may want to uncomment this.
*/
@ -211,18 +211,19 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/**
TEMP_HYSTERESIS: actual temperature must be target +/- hysteresis before target temperature can be achieved.
NOTE: format is 30.2 fixed point, so value of 20 actually means +/- 5 degrees
*/
#define TEMP_HYSTERESIS 20
/**
TEMP_RESIDENCY_TIME: actual temperature must be close to target for this long before target is achieved
temperature is "achieved" for purposes of M109 and friends when actual temperature is within [hysteresis] of target for [residency] seconds
*/
#define TEMP_HYSTERESIS 20
#define TEMP_RESIDENCY_TIME 60
// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
/// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
// #define TEMP_MAX6675
#define TEMP_THERMISTOR
// #define TEMP_AD595
@ -257,8 +258,10 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PINA5)
* *
\***************************************************************************/
// check if heater responds to changes in target temperature, disable and spit errors if not
// largely untested, please comment in forum if this works, or doesn't work for you!
/** \def HEATER_SANITY_CHECK
check if heater responds to changes in target temperature, disable and spit errors if not
largely untested, please comment in forum if this works, or doesn't work for you!
*/
// #define HEATER_SANITY_CHECK
/***************************************************************************\
@ -287,11 +290,11 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, PINA5)
// name port pin pwm
DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
// and now because the c preprocessor isn't as smart as it could be,
// uncomment the ones you've listed above and comment the rest.
// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
/// and now because the c preprocessor isn't as smart as it could be,
/// uncomment the ones you've listed above and comment the rest.
/// \NOTE these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
/// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
/// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
#define HEATER_EXTRUDER HEATER_extruder
// #define HEATER_BED HEATER_bed
@ -305,7 +308,7 @@ DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
* *
\***************************************************************************/
/*
/** \def REPRAP_HOST_COMPATIBILITY
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.
@ -315,12 +318,12 @@ DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
#define REPRAP_HOST_COMPATIBILITY 20100806
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
/*
/**
Baud rate for the connection to the host. Usually 115200, other common values are 19200, 38400 or 57600.
*/
#define BAUD 115200
/*
/** \def XONXOFF
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
@ -335,7 +338,7 @@ DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
* *
\***************************************************************************/
/*
/** \def DEBUG
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
@ -343,34 +346,38 @@ DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
*/
// #define DEBUG
/*
/** \def BANG_BANG
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
BANG_BANG_ON
PWM value for 'on'
BANG_BANG_OFF
PWM value for 'off'
*/
// #define BANG_BANG
/** \def BANG_BANG_ON
BANG_BANG_ON
PWM value for 'on'
*/
// #define BANG_BANG_ON 200
/** \def BANG_BANG_OFF
BANG_BANG_OFF
PWM value for 'off'
*/
// #define BANG_BANG_OFF 45
/*
/**
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
/*
/** \def DC_EXTRUDER
DC extruder
If you have a DC motor extruder, configure it as a "heater" above and define this value as the index or name. You probably also want to comment out E_STEP_PIN and E_DIR_PIN in the Pinouts section above
*/
// #define DC_EXTRUDER HEATER_motor
// #define DC_EXTRUDER_PWM 180
/*
/** \def USE_WATCHDOG
Teacup 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
@ -381,7 +388,7 @@ DEFINE_HEATER(extruder, PORTD, PIND6, OCR2B)
*/
#define REFERENCE REFERENCE_AVCC
/*
/** \def STEP_INTERRUPT_INTERRUPTIBLE
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
*/

View File

@ -1,5 +1,11 @@
/* Notice to developers: this file is intentionally included twice. */
/** \file
\brief Sample Configuration
\note this sample uses AIO0 for both X_STEP and thermistor, and is intended to be an example only!
*/
/*
CONTENTS
@ -25,14 +31,14 @@
If you want to port this to a new chip, start off with arduino.h and see how you go.
*/
/*
/** \def F_CPU
CPU clock rate
*/
#ifndef F_CPU
#define F_CPU 16000000L
#endif
/*
/** \def HOST
This is the motherboard, as opposed to the extruder. See extruder/ directory for GEN3 extruder firmware
*/
#define HOST
@ -42,16 +48,16 @@
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.
// valid range = 0.020 to 4194.303
/// 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.
/// valid range = 0.020 to 4194.303
#define STEPS_PER_MM_X 320.000
#define STEPS_PER_MM_Y 320.000
#define STEPS_PER_MM_Z 320.000
// http://blog.arcol.hu/?p=157 may help with this next one
/// http://blog.arcol.hu/?p=157 may help with this one
#define STEPS_PER_MM_E 320.000
@ -62,24 +68,24 @@
Units are mm/min
*/
// used for G0 rapid moves and as a cap for all other feedrates
/// 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
#define MAXIMUM_FEEDRATE_E 200
// used when searching endstops and as default feedrate
/// used when searching endstops and as default feedrate
#define SEARCH_FEEDRATE_X 50
#define SEARCH_FEEDRATE_Y 50
#define SEARCH_FEEDRATE_Z 50
#define SEARCH_FEEDRATE_E 50
// this is how many steps to suck back the filament by when we stop. set to zero to disable
/// this is how many steps to suck back the filament by when we stop. set to zero to disable
#define E_STARTSTOP_STEPS 20
/*
Soft axis limits, in mm
undefine if you don't want to use them
/**
Soft axis limits, in mm
undefine if you don't want to use them
*/
#define X_MIN 0.0
@ -103,24 +109,24 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/** \def ACCELERATION_REPRAP
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
/*
/** \def ACCELERATION_RAMPING
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
#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
/// 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
/*
/** \def ACCELERATION_TEMPORAL
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.
@ -150,7 +156,7 @@ undefine if you don't want to use them
#include "arduino.h"
/*
/** \def USE_INTERNAL_PULLUPS
internal pullup resistors
the ATmega has internal pullup resistors on it's input pins which are counterproductive with the commonly used eletronic endstops, so they should be switched off. For other endstops, like mechanical ones, you may want to uncomment this.
*/
@ -207,18 +213,19 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/**
TEMP_HYSTERESIS: actual temperature must be target +/- hysteresis before target temperature can be achieved.
NOTE: format is 30.2 fixed point, so value of 20 actually means +/- 5 degrees
*/
#define TEMP_HYSTERESIS 20
/**
TEMP_RESIDENCY_TIME: actual temperature must be close to target for this long before target is achieved
temperature is "achieved" for purposes of M109 and friends when actual temperature is within [hysteresis] of target for [residency] seconds
*/
#define TEMP_HYSTERESIS 20
#define TEMP_RESIDENCY_TIME 60
// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
/// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
// #define TEMP_MAX6675
#define TEMP_THERMISTOR
// #define TEMP_AD595
@ -255,8 +262,10 @@ DEFINE_TEMP_SENSOR(extruder, TT_THERMISTOR, 0)
* *
\***************************************************************************/
// check if heater responds to changes in target temperature, disable and spit errors if not
// largely untested, please comment in forum if this works, or doesn't work for you!
/** \def HEATER_SANITY_CHECK
check if heater responds to changes in target temperature, disable and spit errors if not
largely untested, please comment in forum if this works, or doesn't work for you!
*/
// #define HEATER_SANITY_CHECK
/***************************************************************************\
@ -289,11 +298,11 @@ DEFINE_HEATER(bed, PORTB, PINB4, OCR0B)
// DEFINE_HEATER(chamber, PORTD, PIND7, OCR2A)
// DEFINE_HEATER(motor, PORTD, PIND6, OCR2B)
// and now because the c preprocessor isn't as smart as it could be,
// uncomment the ones you've listed above and comment the rest.
// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
/// and now because the c preprocessor isn't as smart as it could be,
/// uncomment the ones you've listed above and comment the rest.
/// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
/// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
/// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
#define HEATER_EXTRUDER HEATER_extruder
#define HEATER_BED HEATER_bed
@ -307,7 +316,7 @@ DEFINE_HEATER(bed, PORTB, PINB4, OCR0B)
* *
\***************************************************************************/
/*
/** \def REPRAP_HOST_COMPATIBILITY
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.
@ -317,12 +326,12 @@ DEFINE_HEATER(bed, PORTB, PINB4, OCR0B)
#define REPRAP_HOST_COMPATIBILITY 20100806
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
/*
/**
Baud rate for the connection to the host. Usually 115200, other common values are 19200, 38400 or 57600.
*/
#define BAUD 115200
/*
/** \def XONXOFF
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
@ -337,7 +346,7 @@ DEFINE_HEATER(bed, PORTB, PINB4, OCR0B)
* *
\***************************************************************************/
/*
/** \def DEBUG
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
@ -345,57 +354,62 @@ DEFINE_HEATER(bed, PORTB, PINB4, OCR0B)
*/
// #define DEBUG
/*
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
BANG_BANG_ON
PWM value for 'on'
BANG_BANG_OFF
PWM value for 'off'
/** \def BANG_BANG
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
*/
// #define BANG_BANG
/** \def BANG_BANG_ON
BANG_BANG_ON
PWM value for 'on'
*/
// #define BANG_BANG_ON 200
/** \def BANG_BANG_OFF
BANG_BANG_OFF
PWM value for 'off'
*/
// #define BANG_BANG_OFF 45
/*
/**
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
/*
/** \def DC_EXTRUDER
DC extruder
If you have a DC motor extruder, configure it as a "heater" above and define this value as the index or name. You probably also want to comment out E_STEP_PIN and E_DIR_PIN in the Pinouts section above
*/
// #define DC_EXTRUDER HEATER_motor
// #define DC_EXTRUDER_PWM 180
/*
/** \def USE_WATCHDOG
Teacup 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
/*
/** \def STEP_INTERRUPT_INTERRUPTIBLE
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
\note disable this option if you're using a '168 or for some reason your ram usage is above 90%. This option hugely increases likelihood of stack smashing.
*/
#define STEP_INTERRUPT_INTERRUPTIBLE 1
/*
/**
temperature history count. This is how many temperature readings to keep in order to calculate derivative in PID loop
higher values make PID derivative term more stable at the expense of reaction time
*/
#define TH_COUNT 8
// this is the scaling of internally stored PID values. 1024L is a good value
/// this is the scaling of internally stored PID values. 1024L is a good value
#define PID_SCALE 1024L

View File

@ -1,5 +1,10 @@
/* Notice to developers: this file is intentionally included twice. */
/** \file
\brief RAMPS Sample Configuration
http://reprap.org/wiki/Arduino_Mega_Pololu_Shield
*/
/*
CONTENTS
@ -28,14 +33,14 @@
#error RAMPS has 1280/2560! set your cpu type in Makefile!
#endif
/*
/** \def F_CPU
CPU clock rate
*/
#ifndef F_CPU
#define F_CPU 16000000L
#endif
/*
/** \def HOST
This is the motherboard, as opposed to the extruder. See extruder/ directory for GEN3 extruder firmware
*/
#define HOST
@ -58,7 +63,7 @@
#define STEPS_PER_MM_Y (5.023*MICROSTEPPING_Y)
#define STEPS_PER_MM_Z (416.699*MICROSTEPPING_Z)
// http://blog.arcol.hu/?p=157 may help with this next one
/// http://blog.arcol.hu/?p=157 may help with this one
#define STEPS_PER_MM_E (2.759*MICROSTEPPING_E)
@ -69,25 +74,25 @@
Units are mm/min
*/
// used for G0 rapid moves and as a cap for all other feedrates
/// 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
#define MAXIMUM_FEEDRATE_E 600
// used when searching endstops and as default feedrate
/// used when searching endstops and as default feedrate
#define SEARCH_FEEDRATE_X 50
#define SEARCH_FEEDRATE_Y 50
#define SEARCH_FEEDRATE_Z 1
#define SEARCH_FEEDRATE_E 50
// this is how many steps to suck back the filament by when we stop. set to zero to disable
/// this is how many steps to suck back the filament by when we stop. set to zero to disable
#define E_STARTSTOP_STEPS 0
/*
Soft axis limits, in mm
undefine if you don't want to use them
/**
Soft axis limits, in mm
undefine if you don't want to use them
*/
#define X_MIN 0.0
@ -111,24 +116,24 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/** \def ACCELERATION_REPRAP
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
// #define ACCELERATION_REPRAP
/*
/** \def ACCELERATION_RAMPING
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
#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
/// 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
/*
/** \def ACCELERATION_TEMPORAL
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.
@ -158,7 +163,7 @@ undefine if you don't want to use them
#include "arduino.h"
/*
/** \def USE_INTERNAL_PULLUPS
internal pullup resistors
the ATmega has internal pullup resistors on it's input pins which are counterproductive with the commonly used eletronic endstops, so they should be switched off. For other endstops, like mechanical ones, you may want to uncomment this.
*/
@ -217,18 +222,19 @@ undefine if you don't want to use them
* *
\***************************************************************************/
/*
/**
TEMP_HYSTERESIS: actual temperature must be target +/- hysteresis before target temperature can be achieved.
NOTE: format is 30.2 fixed point, so value of 20 actually means +/- 5 degrees
TEMP_RESIDENCY_TIME: actual temperature must be close to target for this long before target is achieved
temperature is "achieved" for purposes of M109 and friends when actual temperature is within [hysteresis] of target for [residency] seconds
*/
#define TEMP_HYSTERESIS 20
/**
TEMP_RESIDENCY_TIME: actual temperature must be close to target for this long before target is achieved
temperature is "achieved" for purposes of M109 and friends when actual temperature is within [hysteresis] of target for [residency] seconds
*/
#define TEMP_RESIDENCY_TIME 60
// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
/// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
// #define TEMP_MAX6675
#define TEMP_THERMISTOR
// #define TEMP_AD595
@ -262,8 +268,10 @@ DEFINE_TEMP_SENSOR(bed, TT_THERMISTOR, AIO1_PIN)
* *
\***************************************************************************/
// check if heater responds to changes in target temperature, disable and spit errors if not
// largely untested, please comment in forum if this works, or doesn't work for you!
/** \def HEATER_SANITY_CHECK
check if heater responds to changes in target temperature, disable and spit errors if not
largely untested, please comment in forum if this works, or doesn't work for you!
*/
// #define HEATER_SANITY_CHECK
/***************************************************************************\
@ -297,11 +305,11 @@ DEFINE_HEATER(fan, PORTH, PINH6, OCR2B)
// DEFINE_HEATER(chamber, PORTD, PIND7, OCR2A)
// DEFINE_HEATER(motor, PORTD, PIND6, OCR2B)
// and now because the c preprocessor isn't as smart as it could be,
// uncomment the ones you've listed above and comment the rest.
// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
/// and now because the c preprocessor isn't as smart as it could be,
/// uncomment the ones you've listed above and comment the rest.
/// NOTE: these are used to enable various capability-specific chunks of code, you do NOT need to create new entries unless you are adding new capabilities elsewhere in the code!
/// so if you list a bed above, uncomment HEATER_BED, but if you list a chamber you do NOT need to create HEATED_CHAMBER
/// I have searched high and low for a way to make the preprocessor do this for us, but so far I have not found a way.
#define HEATER_EXTRUDER HEATER_extruder
#define HEATER_BED HEATER_bed
@ -315,7 +323,7 @@ DEFINE_HEATER(fan, PORTH, PINH6, OCR2B)
* *
\***************************************************************************/
/*
/** \def REPRAP_HOST_COMPATIBILITY
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.
@ -325,12 +333,12 @@ DEFINE_HEATER(fan, PORTH, PINH6, OCR2B)
#define REPRAP_HOST_COMPATIBILITY 20100806
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
/*
/**
Baud rate for the connection to the host. Usually 115200, other common values are 19200, 38400 or 57600.
*/
#define BAUD 115200
/*
/** \def XONXOFF
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
@ -345,7 +353,7 @@ DEFINE_HEATER(fan, PORTH, PINH6, OCR2B)
* *
\***************************************************************************/
/*
/** \def DEBUG
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
@ -353,57 +361,61 @@ DEFINE_HEATER(fan, PORTH, PINH6, OCR2B)
*/
// #define DEBUG
/*
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
BANG_BANG_ON
PWM value for 'on'
BANG_BANG_OFF
PWM value for 'off'
/** \def BANG_BANG
BANG_BANG
drops PID loop from heater control, reduces code size significantly (1300 bytes!)
may allow DEBUG on '168
*/
// #define BANG_BANG
/** \def BANG_BANG_ON
BANG_BANG_ON
PWM value for 'on'
*/
// #define BANG_BANG_ON 200
/** \def BANG_BANG_OFF
BANG_BANG_OFF
PWM value for 'off'
*/
// #define BANG_BANG_OFF 45
/*
/**
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
/*
/** \def DC_EXTRUDER
DC extruder
If you have a DC motor extruder, configure it as a "heater" above and define this value as the index or name. You probably also want to comment out E_STEP_PIN and E_DIR_PIN in the Pinouts section above
*/
// #define DC_EXTRUDER HEATER_motor
// #define DC_EXTRUDER_PWM 180
/*
/** \def USE_WATCHDOG
Teacup 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
/*
/**
temperature history count. This is how many temperature readings to keep in order to calculate derivative in PID loop
higher values make PID derivative term more stable at the expense of reaction time
*/
#define TH_COUNT 8
// this is the scaling of internally stored PID values. 1024L is a good value
/// this is the scaling of internally stored PID values. 1024L is a good value
#define PID_SCALE 1024L

13
crc.c
View File

@ -1,7 +1,13 @@
#include "crc.h"
/** \file
\brief crc16 routine
*/
#include <util/crc16.h>
// avr-libc's _crc16_update is equivalent to the following:
//
// uint16_t _crc16_update(uint16_t crc, uint8_t a) {
// int i;
// crc ^= a;
@ -15,6 +21,13 @@
// return crc;
// }
/** block-at-once CRC16 calculator
\param *data data to find crc16 for
\param len length of data
\return uint16 crc16 of passed data
uses avr-libc's optimised crc16 routine
*/
uint16_t crc_block(void *data, uint16_t len) {
uint16_t crc = 0;
for (; len; data++, len--) {

88
dda.c
View File

@ -1,5 +1,9 @@
#include "dda.h"
/** \file
\brief Digital differential analyser - this is where we figure out which steppers need to move, and when they need to move
*/
#include <string.h>
#include <stdlib.h>
#include <avr/interrupt.h>
@ -18,25 +22,30 @@
#include "heater.h"
#endif
/*
Used in distance calculation during DDA setup
*/
// Used in distance calculation during DDA setup
/// micrometers per step X
#define UM_PER_STEP_X 1000L / ((uint32_t) STEPS_PER_MM_X)
/// micrometers per step Y
#define UM_PER_STEP_Y 1000L / ((uint32_t) STEPS_PER_MM_Y)
/// micrometers per step Z
#define UM_PER_STEP_Z 1000L / ((uint32_t) STEPS_PER_MM_Z)
/// micrometers per step E
#define UM_PER_STEP_E 1000L / ((uint32_t) STEPS_PER_MM_E)
/*
step timeout
*/
/// step timeout
uint8_t steptimeout = 0;
/*
position tracking
*/
/// \var startpoint
/// \brief target position of last move in queue
TARGET startpoint __attribute__ ((__section__ (".bss")));
/// \var current_position
/// \brief actual position of extruder head
/// \todo make current_position = real_position (from endstops) + offset from G28 and friends
TARGET current_position __attribute__ ((__section__ (".bss")));
/*
@ -44,6 +53,13 @@ TARGET current_position __attribute__ ((__section__ (".bss")));
*/
// courtesy of http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml
/*! linear approximation 2d distance formula
\param dx distance in X plane
\param dy distance in Y plane
\return 3-part linear approximation of \f$\sqrt{\Delta x^2 + \Delta y^2}\f$
see http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml
*/
uint32_t approx_distance( uint32_t dx, uint32_t dy )
{
uint32_t min, max, approx;
@ -66,6 +82,14 @@ uint32_t approx_distance( uint32_t dx, uint32_t dy )
}
// courtesy of http://www.oroboro.com/rafael/docserv.php/index/programming/article/distance
/*! linear approximation 3d distance formula
\param dx distance in X plane
\param dy distance in Y plane
\param dz distance in Z plane
\return 3-part linear approximation of \f$\sqrt{\Delta x^2 + \Delta y^2 + \Delta z^2}\f$
see http://www.oroboro.com/rafael/docserv.php/index/programming/article/distance
*/
uint32_t approx_distance_3( uint32_t dx, uint32_t dy, uint32_t dz )
{
uint32_t min, med, max, approx;
@ -100,6 +124,13 @@ uint32_t approx_distance_3( uint32_t dx, uint32_t dy, uint32_t dz )
return (( approx + 512 ) >> 10 );
}
/*!
integer square root algorithm
\param a find square root of this number
\return sqrt(a - 1) < returnvalue <= sqrt(a)
see http://www.embedded-systems.com/98/9802fe2.htm
*/
// courtesy of http://www.embedded-systems.com/98/9802fe2.htm
uint16_t int_sqrt(uint32_t a) {
uint32_t rem = 0;
@ -123,6 +154,10 @@ uint16_t int_sqrt(uint32_t a) {
// this is an ultra-crude pseudo-logarithm routine, such that:
// 2 ^ msbloc(v) >= v
/*! crude logarithm algorithm
\param v value to find \f$log_2\f$ of
\return floor(log(v) / log(2))
*/
const uint8_t msbloc (uint32_t v) {
uint8_t i;
uint32_t c;
@ -134,10 +169,18 @@ const uint8_t msbloc (uint32_t v) {
return 0;
}
/*
CREATE a dda given current_position and a target, save to passed location so we can write directly into the queue
*/
/*! CREATE a dda given current_position and a target, save to passed location so we can write directly into the queue
\param *dda pointer to a dda_queue entry to overwrite
\param *target the target position of this move
\ref startpoint the beginning position of this move
This function does a /lot/ of math. It works out directions for each axis, distance travelled, the time between the first and second step
It also pre-fills any data that the selected accleration algorithm needs, and can be pre-computed for the whole move.
This algorithm is probably the main limiting factor to print speed in terms of firmware limitations
*/
void dda_create(DDA *dda, TARGET *target) {
uint32_t distance, c_limit, c_limit_calc;
@ -340,10 +383,15 @@ void dda_create(DDA *dda, TARGET *target) {
startpoint.E = 0;
}
/*
Start a prepared DDA
*/
/*! Start a prepared DDA
\param *dda pointer to entry in dda_queue to start
This function actually begins the move described by the passed DDA entry.
We set direction and enable outputs, and set the timer for the first step from the precalculated value.
We also mark this DDA as running, so other parts of the firmware know that something is happening
*/
void dda_start(DDA *dda) {
// called from interrupt context: keep it simple!
if (dda->nullmove) {
@ -384,10 +432,18 @@ void dda_start(DDA *dda) {
}
}
/*
STEP
*/
/*! STEP
\param *dda the current move
This is called from our timer interrupt every time a step needs to occur.
We first work out which axes need to step, and generate step pulses for them
Then we re-enable global interrupts so serial data reception and other important things can occur while we do some math.
Next, we work out how long until our next step using the selected acceleration algorithm and set the timer.
Then we decide if this was the last step for this move, and if so mark this dda as dead so next timer interrupt we can start a new one.
Finally we de-assert any asserted step pins.
\todo take into account the time that interrupt takes to run
*/
void dda_step(DDA *dda) {
// called from interrupt context! keep it as simple as possible
uint8_t did_step = 0;

72
dda.h
View File

@ -34,68 +34,79 @@ typedef struct {
uint32_t F;
} TARGET;
// this is a digital differential analyser data struct
/**
\struct DDA
\brief this is a digital differential analyser data struct
This struct holds all the details of an individual multi-axis move, including pre-calculated acceleration data.
This struct is filled in by dda_create(), called from enqueue(), called mostly from gcode_process() and from a few other places too (eg \file homing.c)
*/
typedef struct {
// this is where we should finish
/// this is where we should finish
TARGET endpoint;
union {
struct {
// status fields
uint8_t nullmove :1;
uint8_t live :1;
uint8_t nullmove :1; ///< bool: no axes move, maybe we wait for temperatures or change speed
uint8_t live :1; ///< bool: this DDA is running and still has steps to do
#ifdef ACCELERATION_REPRAP
uint8_t accel :1;
uint8_t accel :1; ///< bool: speed changes during this move, run accel code
#endif
// wait for temperature to stabilise flag
uint8_t waitfor_temp :1;
uint8_t waitfor_temp :1; ///< bool: wait for temperatures to reach their set values
// directions
uint8_t x_direction :1;
uint8_t y_direction :1;
uint8_t z_direction :1;
uint8_t e_direction :1;
uint8_t x_direction :1; ///< direction flag for X axis
uint8_t y_direction :1; ///< direction flag for Y axis
uint8_t z_direction :1; ///< direction flag for Z axis
uint8_t e_direction :1; ///< direction flag for E axis
};
uint8_t allflags; // used for clearing all flags
uint8_t allflags; ///< used for clearing all flags
};
// distances
uint32_t x_delta;
uint32_t y_delta;
uint32_t z_delta;
uint32_t e_delta;
uint32_t x_delta; ///< number of steps on X axis
uint32_t y_delta; ///< number of steps on Y axis
uint32_t z_delta; ///< number of steps on Z axis
uint32_t e_delta; ///< number of steps on E axis
// bresenham counters
int32_t x_counter;
int32_t y_counter;
int32_t z_counter;
int32_t e_counter;
int32_t x_counter; ///< counter for total_steps vs this axis, used for bresenham calculations.
int32_t y_counter; ///< counter for total_steps vs this axis, used for bresenham calculations.
int32_t z_counter; ///< counter for total_steps vs this axis, used for bresenham calculations.
int32_t e_counter; ///< counter for total_steps vs this axis, used for bresenham calculations.
// total number of steps: set to max(x_delta, y_delta, z_delta, e_delta)
/// total number of steps: set to \f$\max(\Delta x, \Delta y, \Delta z, \Delta e)\f$
uint32_t total_steps;
// linear acceleration variables: c and end_c are 24.8 fixed point timer values, n is the tracking variable
uint32_t c;
uint32_t c; ///< time until next step
#ifdef ACCELERATION_REPRAP
uint32_t end_c;
int32_t n;
uint32_t end_c; ///< time between 2nd last step and last step
int32_t n; ///< precalculated step time offset variable. At every step we calculate \f$c = c - (2 c / n)\f$; \f$n+=4\f$. See http://www.embedded.com/columns/technicalinsights/56800129?printable=true for full description
#endif
#ifdef ACCELERATION_RAMPING
// start of down-ramp, intitalized with total_steps / 2
/// start of down-ramp, intitalized with total_steps / 2
uint32_t ramp_steps;
// counts actual steps done
/// counts actual steps done
uint32_t step_no;
// 24.8 fixed point timer value, maximum speed
/// 24.8 fixed point timer value, maximum speed
uint32_t c_min;
// tracking variable
/// tracking variable
int32_t n;
/// keep track of whether we're ramping up, down, or plateauing
ramp_state_t ramp_state;
#endif
#ifdef ACCELERATION_TEMPORAL
/// time between steps on X axis
uint32_t x_step_interval;
/// time between steps on Y axis
uint32_t y_step_interval;
/// time between steps on Z axis
uint32_t z_step_interval;
/// time between steps on E axis
uint32_t e_step_interval;
#endif
} DDA;
@ -104,14 +115,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
/// 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 endpoint of the most recently created DDA, so we know where the next one created starts
// could also be called last_endpoint
/// startpoint holds the endpoint of the most recently created DDA, so we know where the next one created starts. could also be called last_endpoint
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.
/// 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;
/*

View File

@ -1,5 +1,9 @@
#include "dda_queue.h"
/** \file
\brief DDA Queue - manage the move queue
*/
#include <string.h>
#include <avr/interrupt.h>
@ -12,14 +16,22 @@
#include "sersendf.h"
#include "clock.h"
/// movebuffer head pointer. Points to the last move in the queue.
uint8_t mb_head = 0;
/// movebuffer tail pointer. Points to the currently executing move
uint8_t mb_tail = 0;
/// move buffer.
/// holds move queue
DDA movebuffer[MOVEBUFFER_SIZE] __attribute__ ((__section__ (".bss")));
/// check if the queue is completely full
uint8_t queue_full() {
return (((mb_tail - mb_head - 1) & (MOVEBUFFER_SIZE - 1)) == 0)?255:0;
}
/// check if the queue is completely empty
uint8_t queue_empty() {
return ((mb_tail == mb_head) && (movebuffer[mb_tail].live == 0))?255:0;
}
@ -28,6 +40,7 @@ uint8_t queue_empty() {
// This is the one function called by the timer interrupt.
// It calls a few other functions, though.
// -------------------------------------------------------
/// Take a step or go to the next move.
void queue_step() {
// do our next step
if (movebuffer[mb_tail].live) {
@ -54,6 +67,8 @@ void queue_step() {
next_move();
}
/// add a move to the movebuffer
/// \note this function waits for space to be available if necessary, check queue_full() first if waiting is a problem
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())
@ -85,7 +100,8 @@ void enqueue(TARGET *t) {
next_move();
}
// sometimes called from normal program execution, sometimes from interrupt context
/// go to the next move.
/// be aware that this is sometimes called from interrupt context, sometimes not.
void next_move() {
if (queue_empty() == 0) {
do {
@ -109,10 +125,14 @@ void next_move() {
setTimer(0);
}
/// DEBUG - print queue.
/// Qt/hs format, t is tail, h is head, s is F/full, E/empty or neither
void print_queue() {
sersendf_P(PSTR("Q%d/%d%c"), mb_tail, mb_head, (queue_full()?'F':(queue_empty()?'E':' ')));
}
/// dump queue for emergency stop.
/// \todo effect on startpoint/current_position is undefined!
void queue_flush() {
// save interrupt flag
uint8_t sreg = SREG;
@ -128,6 +148,7 @@ void queue_flush() {
SREG = sreg;
}
/// waits for a space in the queue to become available
void queue_wait() {
for (;queue_empty() == 0;) {
ifclock(CLOCK_FLAG_10MS) {

12
delay.c
View File

@ -1,8 +1,13 @@
#include "delay.h"
/** \file
\brief Delay routines
*/
#include "watchdog.h"
// delay( microseconds )
/// delay microseconds
/// \param delay time to wait in microseconds
void delay(uint32_t delay) {
wd_reset();
while (delay > 65535) {
@ -14,7 +19,8 @@ void delay(uint32_t delay) {
wd_reset();
}
// delay_ms( milliseconds )
/// delay milliseconds
/// \param delay time to wait in milliseconds
void delay_ms(uint32_t delay) {
wd_reset();
while (delay > 65) {
@ -26,6 +32,8 @@ void delay_ms(uint32_t delay) {
wd_reset();
}
/// internal- wait for up to 65.5ms using a busy loop
/// \param us time to wait in microseconds
void delayMicrosecondsInterruptible(uint16_t us)
{
// for a one-microsecond delay, simply return. the overhead

View File

@ -1,10 +1,16 @@
#include "analog.h"
/** \file
\brief Analog subsystem
*/
#include "temp.h"
#include <avr/interrupt.h>
/* OR-combined mask of all channels */
#undef DEFINE_TEMP_SENSOR
//! automagically generate analog_mask from DEFINE_TEMP_SENSOR entries in config.h
#define DEFINE_TEMP_SENSOR(name, type, pin) | (((type == TT_THERMISTOR) || (type == TT_AD595)) ? 1 << (pin) : 0)
static const uint8_t analog_mask = 0
#include "config.h"
@ -14,6 +20,7 @@ static const uint8_t analog_mask = 0
static uint8_t adc_counter;
static volatile uint16_t adc_result[8] __attribute__ ((__section__ (".bss")));
//! Configure all registers, start interrupt loop
void analog_init() {
if (analog_mask > 0) {
#ifdef PRR
@ -36,6 +43,10 @@ void analog_init() {
} /* analog_mask > 0 */
}
/*! Analog Interrupt
This is where we read our analog value and store it in an array for later retrieval
*/
ISR(ADC_vect, ISR_NOBLOCK) {
// emulate free-running mode but be more deterministic about exactly which result we have, since this project has long-running interrupts
if (analog_mask > 0) {
@ -52,6 +63,10 @@ ISR(ADC_vect, ISR_NOBLOCK) {
}
}
/*! Read analog value from saved result array
\param channel Channel to be read
\return analog reading, 10-bit right aligned
*/
uint16_t analog_read(uint8_t channel) {
if (analog_mask > 0) {
uint16_t r;

View File

@ -26,6 +26,7 @@
#endif
void analog_init(void);
uint16_t analog_read(uint8_t channel);
#endif /* _ANALOG_H */

View File

@ -1,3 +1,10 @@
/*!
\file
\brief pin definitions and I/O macros
why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
#ifndef _ARDUINO_H
#define _ARDUINO_H
@ -8,7 +15,8 @@
*/
#ifndef MASK
#define MASK(PIN) (1 << PIN)
/// MASKING- returns \f$2^PIN\f$
#define MASK(PIN) (1 << PIN)
#endif
/*
@ -17,26 +25,40 @@
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
*/
/// Read a pin
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
/// write to a pin
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
/// toggle a pin
#define _TOGGLE(IO) do { IO ## _RPORT = MASK(IO ## _PIN); } while (0)
/// set pin as input
#define _SET_INPUT(IO) do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
/// set pin as output
#define _SET_OUTPUT(IO) do { IO ## _DDR |= MASK(IO ## _PIN); } while (0)
/// check if pin is an input
#define _GET_INPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) == 0)
/// check if pin is an output
#define _GET_OUTPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) != 0)
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
/// Read a pin wrapper
#define READ(IO) _READ(IO)
/// Write to a pin wrapper
#define WRITE(IO, v) _WRITE(IO, v)
/// toggle a pin wrapper
#define TOGGLE(IO) _TOGGLE(IO)
/// set pin as input wrapper
#define SET_INPUT(IO) _SET_INPUT(IO)
/// set pin as output wrapper
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
/// check if pin is an input wrapper
#define GET_INPUT(IO) _GET_INPUT(IO)
/// check if pin is an output wrapper
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
/*
@ -61,6 +83,10 @@
#include "arduino_1280.h" //2560 has the same pins and ports so we can reuse the 1280 file.
#endif
#if defined (__AVR_AT90USB1287__)
#include "arduino_usb1287.h"
#endif
#ifndef DIO0_PIN
#error pins for this chip not defined in arduino.h! If you write an appropriate pin definition and have this firmware work on your chip, please tell us via the forum thread
#endif

View File

@ -1,7 +1,13 @@
#include "crc.h"
/** \file
\brief crc16 routine
*/
#include <util/crc16.h>
// avr-libc's _crc16_update is equivalent to the following:
//
// uint16_t _crc16_update(uint16_t crc, uint8_t a) {
// int i;
// crc ^= a;
@ -15,6 +21,13 @@
// return crc;
// }
/** block-at-once CRC16 calculator
\param *data data to find crc16 for
\param len length of data
\return uint16 crc16 of passed data
uses avr-libc's optimised crc16 routine
*/
uint16_t crc_block(void *data, uint16_t len) {
uint16_t crc = 0;
for (; len; data++, len--) {

View File

@ -1,8 +1,13 @@
#include "delay.h"
/** \file
\brief Delay routines
*/
#include "watchdog.h"
// delay( microseconds )
/// delay microseconds
/// \param delay time to wait in microseconds
void delay(uint32_t delay) {
wd_reset();
while (delay > 65535) {
@ -14,7 +19,8 @@ void delay(uint32_t delay) {
wd_reset();
}
// delay_ms( milliseconds )
/// delay milliseconds
/// \param delay time to wait in milliseconds
void delay_ms(uint32_t delay) {
wd_reset();
while (delay > 65) {
@ -26,6 +32,8 @@ void delay_ms(uint32_t delay) {
wd_reset();
}
/// internal- wait for up to 65.5ms using a busy loop
/// \param us time to wait in microseconds
void delayMicrosecondsInterruptible(uint16_t us)
{
// for a one-microsecond delay, simply return. the overhead

View File

@ -1,5 +1,9 @@
#include "heater.h"
/** \file
\brief Manage heaters
*/
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
@ -13,13 +17,16 @@
#include "sersendf.h"
#endif
/// \struct heater_definition_t
/// \brief simply holds pinout data- port, pin, pwm channel if used
typedef struct {
volatile uint8_t *heater_port;
uint8_t heater_pin;
volatile uint8_t *heater_pwm;
volatile uint8_t *heater_port; ///< pointer to port. DDR is inferred from this pointer too
uint8_t heater_pin; ///< heater pin, not masked. eg for PB3 enter '3' here, or PB3_PIN or similar
volatile uint8_t *heater_pwm; ///< pointer to 8-bit PWM register, eg OCR0A (8-bit) or ORC3L (low byte, 16-bit)
} heater_definition_t;
#undef DEFINE_HEATER
/// \brief helper macro to fill heater definition struct from config.h
#define DEFINE_HEATER(name, port, pin, pwm) { &(port), (pin), &(pwm) },
static const heater_definition_t heaters[NUM_HEATERS] =
{
@ -27,45 +34,62 @@ static const heater_definition_t heaters[NUM_HEATERS] =
};
#undef DEFINE_HEATER
// this struct holds the heater PID factors that are stored in the EEPROM during poweroff
/**
\var heaters_pid
\brief this struct holds the heater PID factors
PID is a fascinating way to control any closed loop control, combining the error (P), cumulative error (I) and rate at which we're approacing the setpoint (D) in such a way that when correctly tuned, the system will achieve target temperature quickly and with little to no overshoot
At every sample, we calculate \f$OUT = k_P (S - T) + k_I \int (S - T) + k_D \frac{dT}{dt}\f$ where S is setpoint and T is temperature.
The three factors kP, kI, kD are chosen to give the desired behaviour given the dynamics of the system.
See http://www.eetimes.com/design/embedded/4211211/PID-without-a-PhD for the full story
*/
struct {
int32_t p_factor;
int32_t i_factor;
int32_t d_factor;
int16_t i_limit;
int32_t p_factor; ///< scaled P factor
int32_t i_factor; ///< scaled I factor
int32_t d_factor; ///< scaled D factor
int16_t i_limit; ///< scaled I limit, such that \f$-i_{limit} < i_{factor} < i_{limit}\f$
} heaters_pid[NUM_HEATERS];
// this struct holds the runtime heater data- PID integrator history, temperature history, sanity checker
/// \brief this struct holds the runtime heater data- PID integrator history, temperature history, sanity checker
struct {
int16_t heater_i;
int16_t heater_i; ///< integrator, \f$-i_{limit} < \sum{\Delta t} < i_{limit}\f$
uint16_t temp_history[TH_COUNT];
uint8_t temp_history_pointer;
uint16_t temp_history[TH_COUNT]; ///< store last TH_COUNT readings in a ring, so we can smooth out our differentiator
uint8_t temp_history_pointer; ///< pointer to last entry in ring
#ifdef HEATER_SANITY_CHECK
uint16_t sanity_counter;
uint16_t sane_temperature;
uint16_t sanity_counter; ///< how long things haven't seemed sane
uint16_t sane_temperature; ///< a temperature we consider sane given the heater settings
#endif
uint8_t heater_output;
uint8_t heater_output; ///< this is the PID value we eventually send to the heater
} heaters_runtime[NUM_HEATERS];
/// default scaled P factor, equivalent to 8.0
#define DEFAULT_P 8192
/// default scaled I factor, equivalent to 0.5
#define DEFAULT_I 512
/// default scaled D factor, equivalent to 24
#define DEFAULT_D 24576
/// default scaled I limit
#define DEFAULT_I_LIMIT 384
// this lives in the eeprom so we can save our PID settings for each heater
/// this lives in the eeprom so we can save our PID settings for each heater
typedef struct {
int32_t EE_p_factor;
int32_t EE_i_factor;
int32_t EE_d_factor;
int16_t EE_i_limit;
uint16_t crc;
uint16_t crc; ///< crc so we can use defaults if eeprom data is invalid
} EE_factor;
EE_factor EEMEM EE_factors[NUM_HEATERS];
/// \brief initialise heater subsystem
/// Set directions, initialise PWM timers, read PID factors from eeprom, etc
void heater_init() {
heater_t i;
// setup pins
@ -115,6 +139,7 @@ void heater_init() {
}
}
/// \brief Write PID factors to eeprom
void heater_save_settings() {
#ifndef BANG_BANG
heater_t i;
@ -128,6 +153,12 @@ void heater_save_settings() {
#endif /* BANG_BANG */
}
/** \brief run heater PID algorithm
\param h which heater we're running the loop for
\param t which temp sensor this heater is attached to
\param current_temp the temperature that the associated temp sensor is reporting
\param target_temp the temperature we're trying to achieve
*/
void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t target_temp) {
uint8_t pid_output;
@ -247,6 +278,12 @@ void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t ta
heater_set(h, pid_output);
}
/** \brief manually set PWM output
\param index the heater we're setting the output for
\param value the PWM value to write
anything done by this function is overwritten by heater_tick above if the heater has an associated temp sensor
*/
void heater_set(heater_t index, uint8_t value) {
if (index >= NUM_HEATERS)
return;
@ -268,6 +305,10 @@ void heater_set(heater_t index, uint8_t value) {
}
}
/** \brief turn off all heaters
for emergency stop
*/
uint8_t heaters_all_off() {
uint8_t i;
for (i = 0; i < NUM_HEATERS; i++) {
@ -278,6 +319,10 @@ uint8_t heaters_all_off() {
return 255;
}
/** \brief set heater P factor
\param index heater to change factor for
\param p scaled P factor
*/
void pid_set_p(heater_t index, int32_t p) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -287,6 +332,10 @@ void pid_set_p(heater_t index, int32_t p) {
#endif /* BANG_BANG */
}
/** \brief set heater I factor
\param index heater to change I factor for
\param i scaled I factor
*/
void pid_set_i(heater_t index, int32_t i) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -296,6 +345,10 @@ void pid_set_i(heater_t index, int32_t i) {
#endif /* BANG_BANG */
}
/** \brief set heater D factor
\param index heater to change D factor for
\param d scaled D factor
*/
void pid_set_d(heater_t index, int32_t d) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -305,6 +358,10 @@ void pid_set_d(heater_t index, int32_t d) {
#endif /* BANG_BANG */
}
/** \brief set heater I limit
\param index heater to set I limit for
\param i_limit scaled I limit
*/
void pid_set_i_limit(heater_t index, int32_t i_limit) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -315,6 +372,9 @@ void pid_set_i_limit(heater_t index, int32_t i_limit) {
}
#ifndef EXTRUDER
/** \brief send heater debug info to host
\param i index of heater to send info for
*/
void heater_print(uint16_t i) {
sersendf_P(PSTR("P:%ld I:%ld D:%ld Ilim:%u crc:%u "), heaters_pid[i].p_factor, heaters_pid[i].i_factor, heaters_pid[i].d_factor, heaters_pid[i].i_limit, crc_block(&heaters_pid[i].p_factor, 14));
}

View File

@ -1,5 +1,9 @@
#include "intercom.h"
/** \file
\brief motherboard <-> extruder board protocol
*/
#include <avr/io.h>
#include <avr/interrupt.h>
@ -11,12 +15,16 @@
#define START 0x55
intercom_packet tx; // this packet will be send
intercom_packet rx; // the last received packet with correct checksum
intercom_packet _tx; // current packet in transmission
intercom_packet _rx; // receiving packet
intercom_packet tx; ///< this packet will be sent
intercom_packet rx; ///< the last received packet with correct checksum
intercom_packet _tx; ///< current packet in transmission
intercom_packet _rx; ///< current packet being received
/// pointer to location in transferring packet.
/// since we run half duplex, we can share the pointer between rx and tx
uint8_t packet_pointer;
/// crc for currently transferring packet
/// since we run half duplex, we can share the crc between rx and tx
uint8_t rxcrc;
volatile uint8_t intercom_flags;

View File

@ -12,26 +12,31 @@
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B &= ~(MASK(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0)
#endif
/// list of error codes, not many so far...
enum {
ERROR_BAD_CRC
} err_codes;
/** \brief intercom packet structure, both tx and rx
*/
typedef struct {
uint8_t start;
uint8_t dio;
uint8_t controller_num;
uint8_t control_word;
uint8_t control_index;
uint8_t start; ///< start byte, must be 0x55
uint8_t dio; ///< gpio
uint8_t controller_num; ///< controller index
uint8_t control_word; ///< what to do
uint8_t control_index; ///< what to do it to
/// data with which to do it
union {
int32_t control_data_int32;
uint32_t control_data_uint32;
float control_data_float;
uint16_t temp[2];
};
uint8_t err;
uint8_t crc;
uint8_t err; ///< error code, if any
uint8_t crc; ///< crc for packet verification. packets with bad crc are simply ignored
} intercom_packet_t;
/// this allows us to fill the packet struct, then pass it to something that expects an array of bytes
typedef union {
intercom_packet_t packet;
uint8_t data[sizeof(intercom_packet_t)];
@ -40,33 +45,33 @@ typedef union {
extern intercom_packet tx;
extern intercom_packet rx;
// initialise serial subsystem
/// initialise serial subsystem
void intercom_init(void);
// if host, send target temperature to extruder
// if extruder, send actual temperature to host
/// if host, send target temperature to extruder
/// if extruder, send actual temperature to host
void send_temperature(uint8_t index, uint16_t temperature);
// if host, read actual temperature from extruder
// if extruder, read target temperature from host
/// if host, read actual temperature from extruder
/// if extruder, read target temperature from host
uint16_t read_temperature(uint8_t index);
// if host, set DIOs on extruder controller
// if extruder, report DIO state
/// if host, set DIOs on extruder controller
/// if extruder, report DIO state
void set_dio(uint8_t index, uint8_t value);
// if host, read extruder DIO inputs
// if extruder, set DIO outputs
/// if host, read extruder DIO inputs
/// if extruder, set DIO outputs
uint8_t get_dio(uint8_t index);
// set error code to send to other end
/// set error code to send to other end
void set_err(uint8_t err);
// get error code sent from other end
/// get error code sent from other end
uint8_t get_err(void);
// if host, send packet to extruder
// if extruder, return packet to host
/// if host, send packet to extruder
/// if extruder, return packet to host
void start_send(void);
#define FLAG_RX_IN_PROGRESS 1

View File

@ -1,5 +1,11 @@
#include "temp.h"
/** \file
\brief Manage temperature sensors
\note \b ALL temperatures are stored as 14.2 fixed point in teacup, so we have a range of 0 - 16383.75 celsius and a precision of 0.25 celsius. That includes the ThermistorTable, which is why you can't copy and paste one from other firmwares which don't do this.
*/
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
@ -20,13 +26,15 @@ typedef enum {
TCOPEN
} temp_flags_enum;
/// holds metadata for each temperature sensor
typedef struct {
temp_type_t temp_type;
uint8_t temp_pin;
heater_t heater;
temp_type_t temp_type; ///< type of sensor
uint8_t temp_pin; ///< pin that sensor is on
heater_t heater; ///< associated heater if any
} temp_sensor_definition_t;
#undef DEFINE_TEMP_SENSOR
/// help build list of sensors from entries in config.h
#define DEFINE_TEMP_SENSOR(name, type, pin) { (type), (pin), (HEATER_ ## name) },
static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] =
{
@ -34,16 +42,16 @@ static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] =
};
#undef DEFINE_TEMP_SENSOR
// this struct holds the runtime sensor data- read temperatures, targets, etc
/// this struct holds the runtime sensor data- read temperatures, targets, etc
struct {
temp_flags_enum temp_flags;
temp_flags_enum temp_flags; ///< flags
uint16_t last_read_temp;
uint16_t target_temp;
uint16_t last_read_temp; ///< last received reading
uint16_t target_temp; ///< manipulate attached heater to attempt to achieve this value
uint8_t temp_residency;
uint8_t temp_residency; ///< how long have we been close to target temperature?
uint16_t next_read_time;
uint16_t next_read_time; ///< how long until we can read this sensor again?
} temp_sensors_runtime[NUM_TEMP_SENSORS];
#ifdef TEMP_MAX6675
@ -58,6 +66,7 @@ struct {
#include "analog.h"
#endif
/// set up temp sensors. Currently only the 'intercom' sensor needs initialisation.
void temp_init() {
temp_sensor_t i;
for (i = 0; i < NUM_TEMP_SENSORS; i++) {
@ -93,6 +102,7 @@ void temp_init() {
}
}
/// called every 10ms from clock.c - check all temp sensors that are ready for checking
void temp_sensor_tick() {
temp_sensor_t i = 0;
for (; i < NUM_TEMP_SENSORS; i++) {
@ -274,6 +284,8 @@ void temp_sensor_tick() {
}
}
/// report whether all temp sensors are reading their target temperatures
/// used for M109 and friends
uint8_t temp_achieved() {
temp_sensor_t i;
uint8_t all_ok = 255;
@ -285,6 +297,9 @@ uint8_t temp_achieved() {
return all_ok;
}
/// specify a target temperature
/// \param index sensor to set a target for
/// \param temperature target temperature to aim for
void temp_set(temp_sensor_t index, uint16_t temperature) {
if (index >= NUM_TEMP_SENSORS)
return;
@ -297,6 +312,8 @@ void temp_set(temp_sensor_t index, uint16_t temperature) {
#endif
}
/// return most recent reading for a sensor
/// \param index sensor to read
uint16_t temp_get(temp_sensor_t index) {
if (index >= NUM_TEMP_SENSORS)
return 0;
@ -306,6 +323,8 @@ uint16_t temp_get(temp_sensor_t index) {
// extruder doesn't have sersendf_P
#ifndef EXTRUDER
/// send temperatures to host
/// \param index sensor value to send
void temp_print(temp_sensor_t index) {
uint8_t c = 0;

View File

@ -1,5 +1,15 @@
#include "timer.h"
/** \file
\brief Timer management - step pulse clock and system clock
Teacup uses timer1 to generate both step pulse clock and system clock.
We achieve this by using the output compare registers to generate the two clocks while the timer free-runs.
Teacup has tried numerous timer management methods, and this is the best so far.
*/
#include <avr/interrupt.h>
#include "arduino.h"
@ -9,20 +19,24 @@
#include "dda_queue.h"
#endif
/*
how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535)
*/
/// how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535)
#define TICK_TIME 2 MS
/// convert back to ms from cpu ticks so our system clock runs properly if you change TICK_TIME
#define TICK_TIME_MS (TICK_TIME / (F_CPU / 1000))
/// time until next step, as output compare register is too small for long step times
volatile uint32_t next_step_time;
/// every time our clock fires, we increment this so we know when 10ms has elapsed
uint8_t clock_counter_10ms = 0;
/// keep track of when 250ms has elapsed
uint8_t clock_counter_250ms = 0;
/// keep track of when 1s has elapsed
uint8_t clock_counter_1s = 0;
/// flags to tell main loop when above have elapsed
volatile uint8_t clock_flag = 0;
// comparator B is the "clock", happens every TICK_TIME
/// comparator B is the system clock, happens every TICK_TIME
ISR(TIMER1_COMPB_vect) {
// set output compare register to the next clock tick
OCR1B = (OCR1B + TICK_TIME) & 0xFFFF;
@ -65,11 +79,10 @@ void timer1_compa_isr() {
WRITE(SCK, 0);
}
// comparator A is the step timer. It has higher priority then B.
/// comparator A is the step timer. It has higher priority then B.
ISR(TIMER1_COMPA_vect) {
// Check if this is a real step, or just a next_step_time "overflow"
if (next_step_time < 65536) {
next_step_time = 0;
// step!
timer1_compa_isr();
return;
@ -88,6 +101,8 @@ ISR(TIMER1_COMPA_vect) {
}
#endif /* ifdef HOST */
/// initialise timer and enable system clock interrupt.
/// step interrupt is enabled later when we start using it
void timer_init()
{
// no outputs
@ -101,6 +116,7 @@ void timer_init()
}
#ifdef HOST
/// specify how long until the step timer should fire
void setTimer(uint32_t delay)
{
// save interrupt flag
@ -157,6 +173,7 @@ void setTimer(uint32_t delay)
SREG = sreg;
}
/// stop timers - emergency stop
void timer_stop() {
// disable all interrupts
TIMSK1 = 0;

View File

@ -1,6 +1,15 @@
#include "watchdog.h"
/** \file
\brief Watchdog - reset if main loop doesn't run for too long
The usefulness of this feature is questionable at best.
What do you think will happen if your avr resets in the middle of a print?
Is that preferable to it simply locking up?
*/
#ifdef USE_WATCHDOG
#include <avr/wdt.h>
@ -26,16 +35,18 @@ ISR(WDT_vect) {
wd_flag |= 1;
}
/// intialise watchdog
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
// 0.5s timeout, interrupt and system reset
wdt_enable(WDTO_500MS);
WDTCSR |= MASK(WDIE);
}
/// reset watchdog. MUST be called every 0.5s after init or avr will reset.
void wd_reset() {
wdt_reset();
if (wd_flag) {

View File

@ -1,5 +1,9 @@
#include "gcode_parse.h"
/** \file
\brief Parse received G-Codes
*/
#include <string.h>
#include "serial.h"
@ -39,12 +43,17 @@
#define STEPS_PER_IN_Z ((uint32_t) ((25.4 * STEPS_PER_MM_Z) + 0.5))
#define STEPS_PER_IN_E ((uint32_t) ((25.4 * STEPS_PER_MM_E) + 0.5))
/// current or previous gcode word
/// for working out what to do with data just received
uint8_t last_field = 0;
/// crude crc macro
#define crc(a, b) (a ^ b)
/// crude floating point data storage
decfloat read_digit __attribute__ ((__section__ (".bss")));
/// this is where we store all the data for the current command before we work out what to do with it
GCODE_COMMAND next_target __attribute__ ((__section__ (".bss")));
/*
@ -73,6 +82,13 @@ GCODE_COMMAND next_target __attribute__ ((__section__ (".bss")));
extern const uint32_t powers[]; // defined in sermsg.c
const int32_t rounding[DECFLOAT_EXP_MAX] = {0, 5, 50, 500};
/// convert a floating point input value into an integer with appropriate scaling.
/// \param *df pointer to floating point structure that holds fp value to convert
/// \param multiplicand multiply by this amount during conversion to integer
/// \param denominator divide by this amount during conversion to integer
///
/// lots of work has been done in exploring this function's limitations in terms of overflow and rounding
/// this work may not be finished
static int32_t decfloat_to_int(decfloat *df, uint32_t multiplicand, uint32_t denominator) {
uint32_t r = df->mantissa;
uint8_t e = df->exponent;
@ -98,12 +114,8 @@ static int32_t decfloat_to_int(decfloat *df, uint32_t multiplicand, uint32_t den
return df->sign ? -(int32_t)r : (int32_t)r;
}
/****************************************************************************
* *
* Character Received - add it to our command *
* *
****************************************************************************/
/// Character Received - add it to our command
/// \param c the next character to process
void gcode_parse_char(uint8_t c) {
// uppercase
if (c >= 'a' && c <= 'z')
@ -350,12 +362,12 @@ void gcode_parse_char(uint8_t c) {
}
else {
sersendf_P(PSTR("rs N%ld Expected checksum %d\n"), next_target.N_expected, next_target.checksum_calculated);
request_resend();
// request_resend();
}
}
else {
sersendf_P(PSTR("rs N%ld Expected line number %ld\n"), next_target.N_expected, next_target.N_expected);
request_resend();
// request_resend();
}
// reset variables

View File

@ -12,15 +12,16 @@
// wether to insist on a checksum
//#define REQUIRE_CHECKSUM
// this is a very crude decimal-based floating point structure.
// a real floating point would at least have signed exponent.
/// this is a very crude decimal-based floating point structure.
/// a real floating point would at least have signed exponent.\n
/// resulting value is \f$ mantissa * 10^{-(exponent - 1)} * ((sign * 2) - 1)\f$
typedef struct {
uint32_t mantissa;
uint8_t exponent :7;
uint8_t sign :1;
uint32_t mantissa; ///< the actual digits of our floating point number
uint8_t exponent :7; ///< scale mantissa by \f$10^{-exponent}\f$
uint8_t sign :1; ///< positive or negative?
} decfloat;
// this holds all the possible data from a received command
/// this holds all the possible data from a received command
typedef struct {
union {
struct {
@ -36,35 +37,35 @@ typedef struct {
uint8_t seen_P :1;
uint8_t seen_T :1;
uint8_t seen_N :1;
uint8_t seen_checksum :1;
uint8_t seen_semi_comment :1;
uint8_t seen_parens_comment :1;
uint8_t option_relative :1;
uint8_t option_inches :1;
uint8_t seen_checksum :1; ///< seen a checksum?
uint8_t seen_semi_comment :1; ///< seen a semicolon?
uint8_t seen_parens_comment :1; ///< seen an open parenthesis
uint8_t option_relative :1; ///< relative or absolute coordinates?
uint8_t option_inches :1; ///< inches or millimeters?
};
uint16_t flags;
};
uint8_t G;
uint8_t M;
TARGET target;
uint8_t G; ///< G command number
uint8_t M; ///< M command number
TARGET target; ///< target position: X, Y, Z, E and F
int16_t S;
uint16_t P;
int16_t S; ///< S word (various uses)
uint16_t P; ///< P word (various uses)
uint8_t T;
uint8_t T; ///< T word (tool index)
uint32_t N;
uint32_t N_expected;
uint32_t N; ///< line number
uint32_t N_expected; ///< expected line number
uint8_t checksum_read;
uint8_t checksum_calculated;
uint8_t checksum_read; ///< checksum in gcode command
uint8_t checksum_calculated; ///< checksum we calculated
} GCODE_COMMAND;
// the command being processed
/// the command being processed
extern GCODE_COMMAND next_target;
// accept the next character and process it
/// accept the next character and process it
void gcode_parse_char(uint8_t c);
// uses the global variable next_target.N

View File

@ -1,5 +1,9 @@
#include "gcode_process.h"
/** \file
\brief Work out what to do with received G-Code commands
*/
#include <string.h>
#include "gcode_parse.h"
@ -19,9 +23,10 @@
#include "config.h"
#include "home.h"
// the current tool
/// the current tool
uint8_t tool;
// the tool to be changed when we get an M6
/// the tool to be changed when we get an M6
uint8_t next_tool;
@ -31,6 +36,7 @@ uint8_t next_tool;
this is where we construct a move without a gcode command, useful for gcodes which require multiple moves eg; homing
*/
/// move to X = 0
static void zero_x(void) {
TARGET t = startpoint;
t.X = 0;
@ -38,6 +44,7 @@ static void zero_x(void) {
enqueue(&t);
}
/// move to Y = 0
static void zero_y(void) {
TARGET t = startpoint;
t.Y = 0;
@ -45,6 +52,7 @@ static void zero_y(void) {
enqueue(&t);
}
/// move to Z = 0
static void zero_z(void) {
TARGET t = startpoint;
t.Z = 0;
@ -52,6 +60,7 @@ static void zero_z(void) {
enqueue(&t);
}
/// move E by a certain amount at a certain speed
static void SpecialMoveE(int32_t e, uint32_t f) {
TARGET t = startpoint;
t.E = e;
@ -59,11 +68,15 @@ static void SpecialMoveE(int32_t e, uint32_t f) {
enqueue(&t);
}
/****************************************************************************
* *
* Command Received - process it *
* *
****************************************************************************/
/************************************************************************//**
\brief Processes command stored in global \ref next_target.
This is where we work out what to actually do with each command we
receive. All data has already been scaled to integers in gcode_process.
If you want to add support for a new G or M code, this is the place.
*//*************************************************************************/
void process_gcode_command() {
uint32_t backup_f;

View File

@ -1,5 +1,9 @@
#include "heater.h"
/** \file
\brief Manage heaters
*/
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
@ -13,13 +17,16 @@
#include "sersendf.h"
#endif
/// \struct heater_definition_t
/// \brief simply holds pinout data- port, pin, pwm channel if used
typedef struct {
volatile uint8_t *heater_port;
uint8_t heater_pin;
volatile uint8_t *heater_pwm;
volatile uint8_t *heater_port; ///< pointer to port. DDR is inferred from this pointer too
uint8_t heater_pin; ///< heater pin, not masked. eg for PB3 enter '3' here, or PB3_PIN or similar
volatile uint8_t *heater_pwm; ///< pointer to 8-bit PWM register, eg OCR0A (8-bit) or ORC3L (low byte, 16-bit)
} heater_definition_t;
#undef DEFINE_HEATER
/// \brief helper macro to fill heater definition struct from config.h
#define DEFINE_HEATER(name, port, pin, pwm) { &(port), (pin), &(pwm) },
static const heater_definition_t heaters[NUM_HEATERS] =
{
@ -27,45 +34,62 @@ static const heater_definition_t heaters[NUM_HEATERS] =
};
#undef DEFINE_HEATER
// this struct holds the heater PID factors that are stored in the EEPROM during poweroff
/**
\var heaters_pid
\brief this struct holds the heater PID factors
PID is a fascinating way to control any closed loop control, combining the error (P), cumulative error (I) and rate at which we're approacing the setpoint (D) in such a way that when correctly tuned, the system will achieve target temperature quickly and with little to no overshoot
At every sample, we calculate \f$OUT = k_P (S - T) + k_I \int (S - T) + k_D \frac{dT}{dt}\f$ where S is setpoint and T is temperature.
The three factors kP, kI, kD are chosen to give the desired behaviour given the dynamics of the system.
See http://www.eetimes.com/design/embedded/4211211/PID-without-a-PhD for the full story
*/
struct {
int32_t p_factor;
int32_t i_factor;
int32_t d_factor;
int16_t i_limit;
int32_t p_factor; ///< scaled P factor
int32_t i_factor; ///< scaled I factor
int32_t d_factor; ///< scaled D factor
int16_t i_limit; ///< scaled I limit, such that \f$-i_{limit} < i_{factor} < i_{limit}\f$
} heaters_pid[NUM_HEATERS];
// this struct holds the runtime heater data- PID integrator history, temperature history, sanity checker
/// \brief this struct holds the runtime heater data- PID integrator history, temperature history, sanity checker
struct {
int16_t heater_i;
int16_t heater_i; ///< integrator, \f$-i_{limit} < \sum{\Delta t} < i_{limit}\f$
uint16_t temp_history[TH_COUNT];
uint8_t temp_history_pointer;
uint16_t temp_history[TH_COUNT]; ///< store last TH_COUNT readings in a ring, so we can smooth out our differentiator
uint8_t temp_history_pointer; ///< pointer to last entry in ring
#ifdef HEATER_SANITY_CHECK
uint16_t sanity_counter;
uint16_t sane_temperature;
uint16_t sanity_counter; ///< how long things haven't seemed sane
uint16_t sane_temperature; ///< a temperature we consider sane given the heater settings
#endif
uint8_t heater_output;
uint8_t heater_output; ///< this is the PID value we eventually send to the heater
} heaters_runtime[NUM_HEATERS];
/// default scaled P factor, equivalent to 8.0
#define DEFAULT_P 8192
/// default scaled I factor, equivalent to 0.5
#define DEFAULT_I 512
/// default scaled D factor, equivalent to 24
#define DEFAULT_D 24576
/// default scaled I limit
#define DEFAULT_I_LIMIT 384
// this lives in the eeprom so we can save our PID settings for each heater
/// this lives in the eeprom so we can save our PID settings for each heater
typedef struct {
int32_t EE_p_factor;
int32_t EE_i_factor;
int32_t EE_d_factor;
int16_t EE_i_limit;
uint16_t crc;
uint16_t crc; ///< crc so we can use defaults if eeprom data is invalid
} EE_factor;
EE_factor EEMEM EE_factors[NUM_HEATERS];
/// \brief initialise heater subsystem
/// Set directions, initialise PWM timers, read PID factors from eeprom, etc
void heater_init() {
heater_t i;
// setup pins
@ -115,6 +139,7 @@ void heater_init() {
}
}
/// \brief Write PID factors to eeprom
void heater_save_settings() {
#ifndef BANG_BANG
heater_t i;
@ -128,6 +153,12 @@ void heater_save_settings() {
#endif /* BANG_BANG */
}
/** \brief run heater PID algorithm
\param h which heater we're running the loop for
\param t which temp sensor this heater is attached to
\param current_temp the temperature that the associated temp sensor is reporting
\param target_temp the temperature we're trying to achieve
*/
void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t target_temp) {
uint8_t pid_output;
@ -247,6 +278,12 @@ void heater_tick(heater_t h, temp_sensor_t t, uint16_t current_temp, uint16_t ta
heater_set(h, pid_output);
}
/** \brief manually set PWM output
\param index the heater we're setting the output for
\param value the PWM value to write
anything done by this function is overwritten by heater_tick above if the heater has an associated temp sensor
*/
void heater_set(heater_t index, uint8_t value) {
if (index >= NUM_HEATERS)
return;
@ -268,6 +305,10 @@ void heater_set(heater_t index, uint8_t value) {
}
}
/** \brief turn off all heaters
for emergency stop
*/
uint8_t heaters_all_off() {
uint8_t i;
for (i = 0; i < NUM_HEATERS; i++) {
@ -278,6 +319,10 @@ uint8_t heaters_all_off() {
return 255;
}
/** \brief set heater P factor
\param index heater to change factor for
\param p scaled P factor
*/
void pid_set_p(heater_t index, int32_t p) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -287,6 +332,10 @@ void pid_set_p(heater_t index, int32_t p) {
#endif /* BANG_BANG */
}
/** \brief set heater I factor
\param index heater to change I factor for
\param i scaled I factor
*/
void pid_set_i(heater_t index, int32_t i) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -296,6 +345,10 @@ void pid_set_i(heater_t index, int32_t i) {
#endif /* BANG_BANG */
}
/** \brief set heater D factor
\param index heater to change D factor for
\param d scaled D factor
*/
void pid_set_d(heater_t index, int32_t d) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -305,6 +358,10 @@ void pid_set_d(heater_t index, int32_t d) {
#endif /* BANG_BANG */
}
/** \brief set heater I limit
\param index heater to set I limit for
\param i_limit scaled I limit
*/
void pid_set_i_limit(heater_t index, int32_t i_limit) {
#ifndef BANG_BANG
if (index >= NUM_HEATERS)
@ -315,6 +372,9 @@ void pid_set_i_limit(heater_t index, int32_t i_limit) {
}
#ifndef EXTRUDER
/** \brief send heater debug info to host
\param i index of heater to send info for
*/
void heater_print(uint16_t i) {
sersendf_P(PSTR("P:%ld I:%ld D:%ld Ilim:%u crc:%u "), heaters_pid[i].p_factor, heaters_pid[i].i_factor, heaters_pid[i].d_factor, heaters_pid[i].i_limit, crc_block(&heaters_pid[i].p_factor, 14));
}

11
home.c
View File

@ -1,10 +1,15 @@
#include "home.h"
/** \file
\brief Homing routines
*/
#include "dda.h"
#include "dda_queue.h"
#include "delay.h"
#include "pinio.h"
/// home all 3 axes
void home() {
queue_wait();
@ -27,6 +32,7 @@ void home() {
#endif
}
/// find X MIN endstop
void home_x_negative() {
#if defined X_MIN_PIN
uint8_t denoise_count = 0;
@ -66,6 +72,7 @@ void home_x_negative() {
#endif
}
/// find X_MAX endstop
void home_x_positive() {
#if defined X_MAX_PIN
uint8_t denoise_count = 0;
@ -110,6 +117,7 @@ void home_x_positive() {
#endif
}
/// fund Y MIN endstop
void home_y_negative() {
#if defined Y_MIN_PIN
uint8_t denoise_count = 0;
@ -149,6 +157,7 @@ void home_y_negative() {
#endif
}
/// find Y MAX endstop
void home_y_positive() {
#if defined Y_MAX_PIN
uint8_t denoise_count = 0;
@ -193,6 +202,7 @@ void home_y_positive() {
#endif
}
/// find Z MIN endstop
void home_z_negative() {
#if defined Z_MIN_PIN
uint8_t denoise_count = 0;
@ -233,6 +243,7 @@ void home_z_negative() {
#endif
}
/// find Z MAX endstop
void home_z_positive() {
#if defined Z_MAX_PIN
uint8_t denoise_count = 0;

View File

@ -1,5 +1,9 @@
#include "intercom.h"
/** \file
\brief motherboard <-> extruder board protocol
*/
#include <avr/io.h>
#include <avr/interrupt.h>
@ -11,12 +15,16 @@
#define START 0x55
intercom_packet tx; // this packet will be send
intercom_packet rx; // the last received packet with correct checksum
intercom_packet _tx; // current packet in transmission
intercom_packet _rx; // receiving packet
intercom_packet tx; ///< this packet will be sent
intercom_packet rx; ///< the last received packet with correct checksum
intercom_packet _tx; ///< current packet in transmission
intercom_packet _rx; ///< current packet being received
/// pointer to location in transferring packet.
/// since we run half duplex, we can share the pointer between rx and tx
uint8_t packet_pointer;
/// crc for currently transferring packet
/// since we run half duplex, we can share the crc between rx and tx
uint8_t rxcrc;
volatile uint8_t intercom_flags;

View File

@ -12,26 +12,31 @@
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); UCSR0B &= ~(MASK(TXCIE0) | MASK(UDRIE0)); UCSR0B |= MASK(RXEN0); } while(0)
#endif
/// list of error codes, not many so far...
enum {
ERROR_BAD_CRC
} err_codes;
/** \brief intercom packet structure, both tx and rx
*/
typedef struct {
uint8_t start;
uint8_t dio;
uint8_t controller_num;
uint8_t control_word;
uint8_t control_index;
uint8_t start; ///< start byte, must be 0x55
uint8_t dio; ///< gpio
uint8_t controller_num; ///< controller index
uint8_t control_word; ///< what to do
uint8_t control_index; ///< what to do it to
/// data with which to do it
union {
int32_t control_data_int32;
uint32_t control_data_uint32;
float control_data_float;
uint16_t temp[2];
};
uint8_t err;
uint8_t crc;
uint8_t err; ///< error code, if any
uint8_t crc; ///< crc for packet verification. packets with bad crc are simply ignored
} intercom_packet_t;
/// this allows us to fill the packet struct, then pass it to something that expects an array of bytes
typedef union {
intercom_packet_t packet;
uint8_t data[sizeof(intercom_packet_t)];
@ -40,33 +45,33 @@ typedef union {
extern intercom_packet tx;
extern intercom_packet rx;
// initialise serial subsystem
/// initialise serial subsystem
void intercom_init(void);
// if host, send target temperature to extruder
// if extruder, send actual temperature to host
/// if host, send target temperature to extruder
/// if extruder, send actual temperature to host
void send_temperature(uint8_t index, uint16_t temperature);
// if host, read actual temperature from extruder
// if extruder, read target temperature from host
/// if host, read actual temperature from extruder
/// if extruder, read target temperature from host
uint16_t read_temperature(uint8_t index);
// if host, set DIOs on extruder controller
// if extruder, report DIO state
/// if host, set DIOs on extruder controller
/// if extruder, report DIO state
void set_dio(uint8_t index, uint8_t value);
// if host, read extruder DIO inputs
// if extruder, set DIO outputs
/// if host, read extruder DIO inputs
/// if extruder, set DIO outputs
uint8_t get_dio(uint8_t index);
// set error code to send to other end
/// set error code to send to other end
void set_err(uint8_t err);
// get error code sent from other end
/// get error code sent from other end
uint8_t get_err(void);
// if host, send packet to extruder
// if extruder, return packet to host
/// if host, send packet to extruder
/// if extruder, return packet to host
void start_send(void);
#define FLAG_RX_IN_PROGRESS 1

View File

@ -1,3 +1,28 @@
/** \file
\brief Main file - this is where it all starts, and ends
*/
/** \mainpage Teacup Reprap Firmware
\section intro_sec Introduction
Teacup Reprap Firmware (originally named FiveD on Arduino) is a firmware package for numerous reprap electronics sets.
Please see README for a full introduction and long-winded waffle about this project
\section install_sec Installation
\subsection step1 Step 1: Download
\code git clone git://github.com/triffid/Teacup_Firmware \endcode
\subsection step2 Step 2: configure
\code cp config.[yourboardhere].h config.h \endcode
Edit config.h to suit your machone
Edit Makefile to select the correct chip and programming settings
\subsection step3 Step 3: Compile
\code make \endcode
\code make program \endcode
\subsection step4 Step 4: Test!
\code ./func.sh mendel_reset
./func.sh mendel_talk
M115
ctrl+d \endcode
*/
#include <avr/io.h>
#include <avr/interrupt.h>
@ -22,6 +47,7 @@
#include "clock.h"
#include "intercom.h"
/// initialise all I/O - set pins as input or output, turn off unused subsystems, etc
void io_init(void) {
// disable modules we don't use
#ifdef PRR
@ -174,6 +200,7 @@ void io_init(void) {
#endif
}
/// Startup code, run when we come out of reset
void init(void) {
// set up watchdog
wd_init();
@ -211,6 +238,9 @@ void init(void) {
}
/// this is where it all starts, and ends
///
/// just run init(), then run an endless loop where we pass characters from the serial RX buffer to gcode_parse_char() and check the clocks
int main (void)
{
init();

View File

@ -1,3 +1,7 @@
/** \file
\brief I/O primitives - step, enable, direction, endstops etc
*/
#ifndef _PINIO_H
#define _PINIO_H

View File

@ -1,29 +1,52 @@
#include "serial.h"
/** \file
\brief Serial subsystem
Teacup's serial subsystem is a powerful, thoroughly tested and highly modular serial management system.
It uses ringbuffers for both transmit and receive, and intelligently decides whether to wait or drop transmitted characters if the buffer is full.
It also supports XON/XOFF flow control of the receive buffer, to help avoid overruns.
*/
#include <avr/interrupt.h>
#include "config.h"
#include "arduino.h"
/// size of TX and RX buffers. MUST be a \f$2^n\f$ value
#define BUFSIZE 64
/// ascii XOFF character
#define ASCII_XOFF 19
/// ascii XON character
#define ASCII_XON 17
/// rx buffer head pointer. Points to next available space.
volatile uint8_t rxhead = 0;
/// rx buffer tail pointer. Points to last character in buffer
volatile uint8_t rxtail = 0;
/// rx buffer
volatile uint8_t rxbuf[BUFSIZE];
/// tx buffer head pointer. Points to next available space.
volatile uint8_t txhead = 0;
/// tx buffer tail pointer. Points to last character in buffer
volatile uint8_t txtail = 0;
/// tx buffer
volatile uint8_t txbuf[BUFSIZE];
/// check if we can read from this buffer
#define buf_canread(buffer) ((buffer ## head - buffer ## tail ) & (BUFSIZE - 1))
#define buf_canwrite(buffer) ((buffer ## tail - buffer ## head - 1) & (BUFSIZE - 1))
#define buf_push(buffer, data) do { buffer ## buf[buffer ## head] = data; buffer ## head = (buffer ## head + 1) & (BUFSIZE - 1); } while (0)
/// read from buffer
#define buf_pop(buffer, data) do { data = buffer ## buf[buffer ## tail]; buffer ## tail = (buffer ## tail + 1) & (BUFSIZE - 1); } while (0)
/// check if we can write to this buffer
#define buf_canwrite(buffer) ((buffer ## tail - buffer ## head - 1) & (BUFSIZE - 1))
/// write to buffer
#define buf_push(buffer, data) do { buffer ## buf[buffer ## head] = data; buffer ## head = (buffer ## head + 1) & (BUFSIZE - 1); } while (0)
/*
ringbuffer logic:
head = written data pointer
@ -55,6 +78,9 @@ volatile uint8_t txbuf[BUFSIZE];
volatile uint8_t flowflags = FLOWFLAG_SEND_XON;
#endif
/// initialise serial subsystem
///
/// set up baud generator and interrupts, clear buffers
void serial_init()
{
#if BAUD > 38401
@ -75,6 +101,9 @@ void serial_init()
Interrupts
*/
/// receive interrupt
///
/// we have received a character, stuff it in the rx buffer if we can, or drop it if we can't
#ifdef USART_RX_vect
ISR(USART_RX_vect)
#else
@ -101,6 +130,9 @@ ISR(USART0_RX_vect)
#endif
}
/// transmit buffer ready interrupt
///
/// provide the next character to transmit if we can, otherwise disable this interrupt
#ifdef USART_UDRE_vect
ISR(USART_UDRE_vect)
#else
@ -128,11 +160,13 @@ ISR(USART0_UDRE_vect)
Read
*/
/// check how many characters can be read
uint8_t serial_rxchars()
{
return buf_canread(rx);
}
/// read one character
uint8_t serial_popchar()
{
uint8_t c = 0;
@ -156,6 +190,7 @@ uint8_t serial_popchar()
Write
*/
/// send one character
void serial_writechar(uint8_t data)
{
// check if interrupts are enabled
@ -174,6 +209,7 @@ void serial_writechar(uint8_t data)
UCSR0B |= MASK(UDRIE0);
}
/// send a whole block
void serial_writeblock(void *data, int datalen)
{
int i;
@ -182,6 +218,7 @@ void serial_writeblock(void *data, int datalen)
serial_writechar(((uint8_t *) data)[i]);
}
/// send a string- look for null byte instead of expecting a length
void serial_writestr(uint8_t *data)
{
uint8_t i = 0, r;
@ -190,8 +227,8 @@ void serial_writestr(uint8_t *data)
serial_writechar(r);
}
/*
Write from FLASH
/**
Write block from FLASH
Extensions to output flash memory pointers. This prevents the data to
become part of the .data segment instead of the .code segment. That means
@ -200,7 +237,6 @@ void serial_writestr(uint8_t *data)
For single character writes (i.e. '\n' instead of "\n"), using
serial_writechar() directly is the better choice.
*/
void serial_writeblock_P(PGM_P data, int datalen)
{
int i;
@ -209,6 +245,7 @@ void serial_writeblock_P(PGM_P data, int datalen)
serial_writechar(pgm_read_byte(&data[i]));
}
/// Write string from FLASH
void serial_writestr_P(PGM_P data)
{
uint8_t r, i = 0;

View File

@ -1,7 +1,14 @@
#include "sermsg.h"
/** \file sermsg.c
\brief primitives for sending numbers over the serial link
*/
#include "serial.h"
/** write a single hex digit
\param v hex digit to write, higher nibble ignored
*/
void serwrite_hex4(uint8_t v) {
v &= 0xF;
if (v < 10)
@ -10,23 +17,36 @@ void serwrite_hex4(uint8_t v) {
serial_writechar('A' - 10 + v);
}
/** write a pair of hex digits
\param v byte to write. One byte gives two hex digits
*/
void serwrite_hex8(uint8_t v) {
serwrite_hex4(v >> 4);
serwrite_hex4(v & 0x0F);
}
/** write four hex digits
\param v word to write
*/
void serwrite_hex16(uint16_t v) {
serwrite_hex8(v >> 8);
serwrite_hex8(v & 0xFF);
}
/** write eight hex digits
\param v long word to write
*/
void serwrite_hex32(uint32_t v) {
serwrite_hex16(v >> 16);
serwrite_hex16(v & 0xFFFF);
}
/// list of powers of ten, used for dividing down decimal numbers for sending, and also for our crude floating point algorithm
const uint32_t powers[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
/** write decimal digits from a long unsigned int
\param v number to send
*/
void serwrite_uint32(uint32_t v) {
uint8_t e, t;
@ -43,6 +63,9 @@ void serwrite_uint32(uint32_t v) {
while (e--);
}
/** write decimal digits from a long signed int
\param v number to send
*/
void serwrite_int32(int32_t v) {
if (v < 0) {
serial_writechar('-');

View File

@ -1,11 +1,16 @@
#include "sersendf.h"
/** \file sersendf.c
\brief Simplified printf implementation
*/
#include <stdarg.h>
#include <avr/pgmspace.h>
#include "serial.h"
#include "sermsg.h"
/// for sending hex data
PGM_P str_ox = "0x";
// void sersendf(char *format, ...) {
@ -69,6 +74,28 @@ PGM_P str_ox = "0x";
// va_end(args);
// }
/** \brief Simplified printf
\param format pointer to output format specifier string stored in FLASH.
\param ... output data
Implements only a tiny subset of printf's format specifiers :-
%[ls][udcx%]
l - following data is (32 bits)\n
s - following data is short (8 bits)\n
none - following data is 16 bits.
u - unsigned int\n
d - signed int\n
c - character\n
x - hex\n
% - send a literal % character
Example:
\code sersendf_P(PSTR("X:%ld Y:%ld temp:%u.%d flags:%sx Q%su/%su%c\n"), target.X, target.Y, current_temp >> 2, (current_temp & 3) * 25, dda.allflags, mb_head, mb_tail, (queue_full()?'F':(queue_empty()?'E':' '))) \endcode
*/
void sersendf_P(PGM_P format, ...) {
va_list args;
va_start(args, format);

37
temp.c
View File

@ -1,5 +1,11 @@
#include "temp.h"
/** \file
\brief Manage temperature sensors
\note \b ALL temperatures are stored as 14.2 fixed point in teacup, so we have a range of 0 - 16383.75 celsius and a precision of 0.25 celsius. That includes the ThermistorTable, which is why you can't copy and paste one from other firmwares which don't do this.
*/
#include <stdlib.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
@ -20,13 +26,15 @@ typedef enum {
TCOPEN
} temp_flags_enum;
/// holds metadata for each temperature sensor
typedef struct {
temp_type_t temp_type;
uint8_t temp_pin;
heater_t heater;
temp_type_t temp_type; ///< type of sensor
uint8_t temp_pin; ///< pin that sensor is on
heater_t heater; ///< associated heater if any
} temp_sensor_definition_t;
#undef DEFINE_TEMP_SENSOR
/// help build list of sensors from entries in config.h
#define DEFINE_TEMP_SENSOR(name, type, pin) { (type), (pin), (HEATER_ ## name) },
static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] =
{
@ -34,16 +42,16 @@ static const temp_sensor_definition_t temp_sensors[NUM_TEMP_SENSORS] =
};
#undef DEFINE_TEMP_SENSOR
// this struct holds the runtime sensor data- read temperatures, targets, etc
/// this struct holds the runtime sensor data- read temperatures, targets, etc
struct {
temp_flags_enum temp_flags;
temp_flags_enum temp_flags; ///< flags
uint16_t last_read_temp;
uint16_t target_temp;
uint16_t last_read_temp; ///< last received reading
uint16_t target_temp; ///< manipulate attached heater to attempt to achieve this value
uint8_t temp_residency;
uint8_t temp_residency; ///< how long have we been close to target temperature?
uint16_t next_read_time;
uint16_t next_read_time; ///< how long until we can read this sensor again?
} temp_sensors_runtime[NUM_TEMP_SENSORS];
#ifdef TEMP_MAX6675
@ -58,6 +66,7 @@ struct {
#include "analog.h"
#endif
/// set up temp sensors. Currently only the 'intercom' sensor needs initialisation.
void temp_init() {
temp_sensor_t i;
for (i = 0; i < NUM_TEMP_SENSORS; i++) {
@ -93,6 +102,7 @@ void temp_init() {
}
}
/// called every 10ms from clock.c - check all temp sensors that are ready for checking
void temp_sensor_tick() {
temp_sensor_t i = 0;
for (; i < NUM_TEMP_SENSORS; i++) {
@ -274,6 +284,8 @@ void temp_sensor_tick() {
}
}
/// report whether all temp sensors are reading their target temperatures
/// used for M109 and friends
uint8_t temp_achieved() {
temp_sensor_t i;
uint8_t all_ok = 255;
@ -285,6 +297,9 @@ uint8_t temp_achieved() {
return all_ok;
}
/// specify a target temperature
/// \param index sensor to set a target for
/// \param temperature target temperature to aim for
void temp_set(temp_sensor_t index, uint16_t temperature) {
if (index >= NUM_TEMP_SENSORS)
return;
@ -297,6 +312,8 @@ void temp_set(temp_sensor_t index, uint16_t temperature) {
#endif
}
/// return most recent reading for a sensor
/// \param index sensor to read
uint16_t temp_get(temp_sensor_t index) {
if (index >= NUM_TEMP_SENSORS)
return 0;
@ -306,6 +323,8 @@ uint16_t temp_get(temp_sensor_t index) {
// extruder doesn't have sersendf_P
#ifndef EXTRUDER
/// send temperatures to host
/// \param index sensor value to send
void temp_print(temp_sensor_t index) {
uint8_t c = 0;

28
timer.c
View File

@ -1,5 +1,15 @@
#include "timer.h"
/** \file
\brief Timer management - step pulse clock and system clock
Teacup uses timer1 to generate both step pulse clock and system clock.
We achieve this by using the output compare registers to generate the two clocks while the timer free-runs.
Teacup has tried numerous timer management methods, and this is the best so far.
*/
#include <avr/interrupt.h>
#include "arduino.h"
@ -9,20 +19,24 @@
#include "dda_queue.h"
#endif
/*
how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535)
*/
/// how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535)
#define TICK_TIME 2 MS
/// convert back to ms from cpu ticks so our system clock runs properly if you change TICK_TIME
#define TICK_TIME_MS (TICK_TIME / (F_CPU / 1000))
/// time until next step, as output compare register is too small for long step times
volatile uint32_t next_step_time;
/// every time our clock fires, we increment this so we know when 10ms has elapsed
uint8_t clock_counter_10ms = 0;
/// keep track of when 250ms has elapsed
uint8_t clock_counter_250ms = 0;
/// keep track of when 1s has elapsed
uint8_t clock_counter_1s = 0;
/// flags to tell main loop when above have elapsed
volatile uint8_t clock_flag = 0;
// comparator B is the "clock", happens every TICK_TIME
/// comparator B is the system clock, happens every TICK_TIME
ISR(TIMER1_COMPB_vect) {
// set output compare register to the next clock tick
OCR1B = (OCR1B + TICK_TIME) & 0xFFFF;
@ -65,7 +79,7 @@ void timer1_compa_isr() {
WRITE(SCK, 0);
}
// comparator A is the step timer. It has higher priority then B.
/// comparator A is the step timer. It has higher priority then B.
ISR(TIMER1_COMPA_vect) {
// Check if this is a real step, or just a next_step_time "overflow"
if (next_step_time < 65536) {
@ -87,6 +101,8 @@ ISR(TIMER1_COMPA_vect) {
}
#endif /* ifdef HOST */
/// initialise timer and enable system clock interrupt.
/// step interrupt is enabled later when we start using it
void timer_init()
{
// no outputs
@ -100,6 +116,7 @@ void timer_init()
}
#ifdef HOST
/// specify how long until the step timer should fire
void setTimer(uint32_t delay)
{
// save interrupt flag
@ -156,6 +173,7 @@ void setTimer(uint32_t delay)
SREG = sreg;
}
/// stop timers - emergency stop
void timer_stop() {
// disable all interrupts
TIMSK1 = 0;

View File

@ -1,6 +1,15 @@
#include "watchdog.h"
/** \file
\brief Watchdog - reset if main loop doesn't run for too long
The usefulness of this feature is questionable at best.
What do you think will happen if your avr resets in the middle of a print?
Is that preferable to it simply locking up?
*/
#ifdef USE_WATCHDOG
#include <avr/wdt.h>
@ -26,16 +35,18 @@ ISR(WDT_vect) {
wd_flag |= 1;
}
/// intialise watchdog
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
// 0.5s timeout, interrupt and system reset
wdt_enable(WDTO_500MS);
WDTCSR |= MASK(WDIE);
}
/// reset watchdog. MUST be called every 0.5s after init or avr will reset.
void wd_reset() {
wdt_reset();
if (wd_flag) {