Merge release-candidate-triffid branch
This commit is contained in:
parent
eca4b0b0ec
commit
096d7dfdf3
125
Makefile
125
Makefile
|
|
@ -4,18 +4,25 @@
|
|||
# #
|
||||
# by Triffid Hunter, Traumflug, jakepoz #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your application #
|
||||
# This firmware is Copyright (C) 2009-2010 Michael Moon aka Triffid_Hunter #
|
||||
# #
|
||||
# This program is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program; if not, write to the Free Software #
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGRAM = mendel
|
||||
|
||||
SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c clock.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your hardware #
|
||||
|
|
@ -23,21 +30,11 @@ SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c clock.c time
|
|||
##############################################################################
|
||||
|
||||
# MCU_TARGET = atmega168
|
||||
MCU_TARGET = atmega328p
|
||||
#MCU_TARGET = atmega644p
|
||||
# MCU_TARGET = atmega328p
|
||||
MCU_TARGET = atmega644p
|
||||
# MCU_TARGET = atmega1280
|
||||
F_CPU = 16000000L
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# These defaults should be ok, change if you need to #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
ARCH = avr-
|
||||
CC = $(ARCH)gcc
|
||||
OBJDUMP = $(ARCH)objdump
|
||||
OBJCOPY = $(ARCH)objcopy
|
||||
# F_CPU = 16000000L
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
|
|
@ -51,16 +48,25 @@ OBJCOPY = $(ARCH)objcopy
|
|||
# enables reprap-style acceleration #
|
||||
# ACCELERATION_RAMPING #
|
||||
# enables start/stop ramping #
|
||||
# ACCELERATION_TEMPORAL #
|
||||
# enables experimental temporal step algorithm - not technically a type of #
|
||||
# acceleration, but since it controls step timing it seems appropriate #
|
||||
# GEN3 #
|
||||
# build for standard reprap electronics instead of your custom rig #
|
||||
# HOST #
|
||||
# this is the motherboard for GEN3- don't touch! Extruder has its own #
|
||||
# Makefile. #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
DEFS = -DF_CPU=$(F_CPU)
|
||||
# DEFS = -DF_CPU=$(F_CPU) -DHOST -DGEN3
|
||||
# DEFS += "-DDEBUG=1"
|
||||
|
||||
OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once
|
||||
# OPTIMIZE = -O0
|
||||
CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps
|
||||
LDFLAGS = -Wl,--as-needed -Wl,--gc-sections
|
||||
##############################################################################
|
||||
# #
|
||||
# Programmer settings for "make program" #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
AVRDUDE = avrdude
|
||||
AVRDUDECONF = /etc/avrdude.conf
|
||||
|
|
@ -73,12 +79,35 @@ AVRDUDECONF = /etc/avrdude.conf
|
|||
# MODE="0660" #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGPORT = /dev/arduino
|
||||
|
||||
# atmega168
|
||||
#PROGBAUD = 19200
|
||||
# atmega328p, 644p, 1280
|
||||
PROGBAUD = 57600
|
||||
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# These defaults should be ok, change if you need to #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGRAM = mendel
|
||||
|
||||
SOURCES = $(PROGRAM).c serial.c dda.c gcode_parse.c gcode_process.c timer.c temp.c sermsg.c dda_queue.c watchdog.c debug.c sersendf.c heater.c analog.c delay.c intercom.c pinio.c clock.c
|
||||
|
||||
ARCH = avr-
|
||||
CC = $(ARCH)gcc
|
||||
OBJDUMP = $(ARCH)objdump
|
||||
OBJCOPY = $(ARCH)objcopy
|
||||
|
||||
OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once -mcall-prologues
|
||||
# OPTIMIZE = -O0
|
||||
CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps
|
||||
LDFLAGS = -Wl,--as-needed -Wl,--gc-sections
|
||||
|
||||
OBJ = $(patsubst %.c,%.o,${SOURCES})
|
||||
|
||||
.PHONY: all program clean size
|
||||
|
|
@ -93,23 +122,32 @@ program: $(PROGRAM).hex config.h
|
|||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U flash:w:$^
|
||||
stty 115200 raw ignbrk -hup -echo ixoff < $(PROGPORT)
|
||||
|
||||
program-fuses:
|
||||
avr-objdump -s -j .fuse mendel.o | perl -ne '/\s0000\s([0-9a-f]{2})/ && print "$$1\n"' > lfuse
|
||||
avr-objdump -s -j .fuse mendel.o | perl -ne '/\s0000\s..([0-9a-f]{2})/ && print "$$1\n"' > hfuse
|
||||
avr-objdump -s -j .fuse mendel.o | perl -ne '/\s0000\s....([0-9a-f]{2})/ && print "$$1\n"' > efuse
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U lfuse:w:lfuse
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U hfuse:w:hfuse
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U efuse:w:efuse
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~
|
||||
rm -f sim
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~ *fuse
|
||||
|
||||
size: $(PROGRAM).elf
|
||||
@echo " SIZE Atmega168 Atmega328p Atmega644"
|
||||
@$(OBJDUMP) -h $^ | perl -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (14 * 1024), 14, $$a * 100 / (30 * 1024), 30, $$a * 100 / (63 * 1024), 63 }'
|
||||
@$(OBJDUMP) -h $^ | perl -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (4 * 1024), 4 }'
|
||||
@$(OBJDUMP) -h $^ | perl -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, $$a * 100 / (1 * 1024), 1, $$a * 100 / (2 * 1024), 2, $$a * 100 / (2 * 1024), 2 }'
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (15 * 1024)), 15, ceil($$a * 100 / (31 * 1024)), 31, ceil($$a * 100 / (63 * 1024)), 63 }'
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (4 * 1024)), 4 }'
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (2 * 1024)), 2 }'
|
||||
|
||||
config.h: config.h.dist
|
||||
@echo "Please review config.h, as config.h.dist is more recent."
|
||||
@echo
|
||||
@diff -bBEuF '^. [[:digit:]]. [[:upper:]]' config.h config.h.dist
|
||||
@false
|
||||
|
||||
%.o: %.c config.h
|
||||
%.o: %.c config.h Makefile
|
||||
@echo " CC $@"
|
||||
@$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $<
|
||||
@$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $(subst .o,.c,$@)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
@echo " LINK $@"
|
||||
|
|
@ -130,24 +168,3 @@ config.h: config.h.dist
|
|||
%.sym: %.elf
|
||||
@echo " SYM $@"
|
||||
@$(OBJDUMP) -t $< | perl -ne 'BEGIN { printf " ADDR NAME SIZE\n"; } /([0-9a-f]+)\s+(\w+)\s+O\s+\.(bss|data)\s+([0-9a-f]+)\s+(\w+)/ && printf "0x%04x %-20s +%d\n", eval("0x$$1") & 0xFFFF, $$5, eval("0x$$4")' | sort -k1 > $@
|
||||
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Simulation #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
SIM_SOURCES = $(PROGRAM).c serial_sim.c dda.c gcode_parse.c gcode_process.c timer_sim.c clock_sim.c temp.c sermsg.c dda_queue.c debug.c sersendf.c heater.c analog_sim.c delay_sim.c simulation.c
|
||||
SIM_HEADERS = config.h serial.h dda.h gcode_parse.h gcode_process.h timer.h clock.h temp.h sermsg.h dda_queue.h debug.h sersendf.h heater.h analog.h delay.h simulation.h
|
||||
|
||||
SIM_OBJ = $(patsubst %.c,%.sim.o,${SIM_SOURCES})
|
||||
SIM_CFLAGS = -g -Wall -Wstrict-prototypes -Os $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fshort-enums
|
||||
|
||||
%.sim.o: %.c $(SIM_HEADERS)
|
||||
@echo " CC $@"
|
||||
@cc -DDEBUG -DSIMULATION -Wa,-adhlns=$(<:.c=.al) -c $(SIM_CFLAGS) -o $@ $<
|
||||
|
||||
sim: $(SIM_OBJ)
|
||||
@echo " LINK $@"
|
||||
@cc $(SIM_CFLAGS) -o $@ $^
|
||||
|
|
|
|||
71
README
71
README
|
|
@ -18,10 +18,25 @@ Rewrite of Reprap Mendel firmware:
|
|||
2) check programming settings in Makefile
|
||||
3) make
|
||||
4) make program
|
||||
4a) if programming blank chip, make program-fuses
|
||||
5) ./sender.sh
|
||||
6) have a play, go to 1) if not right
|
||||
7) try printing something!
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Requirements #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
Compile:
|
||||
gnu make
|
||||
binutils, gcc, etc built for avr target (avr-gcc, avr-as, etc)
|
||||
avr-libc
|
||||
Program:
|
||||
avrdude
|
||||
something that avrdude supports: bootloader, separate programmer, whatever
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# License #
|
||||
|
|
@ -98,30 +113,15 @@ The fixed-point stuff is fun, although we have to manually ensure that the decim
|
|||
|
||||
The PID code in heater.c is probably quite generalisable, and seems to work well when tuned. Google knows of plenty of PID tuning guides.
|
||||
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Simulation #
|
||||
# Resources #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
To compile the simulation code, use
|
||||
|
||||
$ make sim
|
||||
|
||||
The simulation program will open a serial port for communication. If you don't want to connect a null modem cable, you can use 'socat' to connect a virtual serial port to your terminal:
|
||||
|
||||
$ socat -d -d PTY READLINE
|
||||
2010/10/18 20:24:33 socat[3700] N PTY is /dev/pts/2
|
||||
2010/10/18 20:24:33 socat[3700] N using readline on stdin for reading and stdio for writing
|
||||
2010/10/18 20:24:33 socat[3700] N starting data transfer loop with FDs [3,3] and [0,0]
|
||||
|
||||
On the first line of output, socat will tell you the name of the virtual serial port. Pass this as an argument to the simulation program (in another terminal):
|
||||
|
||||
$ ./sim /dev/pts/2
|
||||
|
||||
Now you can send G-codes from the socat terminal. The simulation code will print any data sent via the firmware's serial interface. Stepper positions will be shown in green, counting a rising slope on the pin as one step.
|
||||
|
||||
Forum thread: http://forums.reprap.org/read.php?147,33082
|
||||
Source Repository: http://github.com/triffid/FiveD_on_Arduino
|
||||
Wiki Page: http://objects.reprap.org/wiki/FiveD_on_Arduino
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
|
|
@ -132,11 +132,14 @@ Now you can send G-codes from the socat terminal. The simulation code will print
|
|||
*** analog.[ch]
|
||||
This is the analog subsystem. Only used if you have a thermistor or ad595
|
||||
|
||||
*** arduino.h
|
||||
Pin mappings and helper functions for various arduinos ('168/'328-based and '644-based only so far, feel free to add '1280 and post a patch)
|
||||
*** arduino.h, arduino_[chip].h
|
||||
Pin mappings and helper functions for various atmegas
|
||||
|
||||
*** clock.[ch]
|
||||
A system clock for periodic tasks. Supports a long-running clock, but this is disabled by default as nothing uses it (yet!)
|
||||
Regular functions that run in main loop rather than an interrupt
|
||||
|
||||
*** config.h.dist, config.h
|
||||
Configuration for your electronics and hardware. Copy config.h.dist to config.h, edit config.h to suit
|
||||
|
||||
*** copier.[ch]
|
||||
A totally untested and currently unused chunk of code for copying firmware to another identical chip
|
||||
|
|
@ -150,20 +153,29 @@ The queue of moves received from the host.
|
|||
*** debug.[ch]
|
||||
Debugging aids
|
||||
|
||||
*** delay.[ch]
|
||||
Delay functions
|
||||
|
||||
*** FiveD_on_Arduino.pde
|
||||
Allows firmware to be built in arduino ide
|
||||
|
||||
*** func.sh
|
||||
Lots of host-side shell scripts for talking to firmware
|
||||
|
||||
*** gcode.[ch]
|
||||
Gcode interpreter. Scaling of factors to internally used integer or fixed point happens here too.
|
||||
*** gcode_parse.[ch]
|
||||
Gcode parser. Scaling of factors to internally used integer or fixed point happens here too.
|
||||
|
||||
*** gcode_process.[ch]
|
||||
Gcodes actually get executed here after being parsed.
|
||||
|
||||
*** heater.[ch]
|
||||
Heater management, including PID and PWM algorithms, and some configuration parameters
|
||||
|
||||
*** machine.h
|
||||
Configuration variables to match firmware to your hardware
|
||||
*** intercom.[ch]
|
||||
Gen3 serial link control and communication
|
||||
|
||||
*** LICENSE
|
||||
Gnu GPL2 license
|
||||
|
||||
*** Makefile
|
||||
instructions for make on how to build firmware. has a list of modules to build which may need to be updated every so often
|
||||
|
|
@ -171,15 +183,12 @@ instructions for make on how to build firmware. has a list of modules to build w
|
|||
*** mendel.c
|
||||
Firmware startup and main loop code
|
||||
|
||||
*** pinout.h
|
||||
This file associates various functions with particular pins on your avr
|
||||
*** pinio.h
|
||||
A few I/O primitives
|
||||
|
||||
*** README
|
||||
this file
|
||||
|
||||
*** simulation.[sh]
|
||||
helper code to run the code on any Unix PC
|
||||
|
||||
*** sender.sh
|
||||
A simple talker
|
||||
|
||||
|
|
|
|||
64
analog.c
64
analog.c
|
|
@ -1,15 +1,41 @@
|
|||
#include "analog.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
#ifndef ANALOG_MASK
|
||||
#warning define ANALOG_MASK as a bitmask of all the analog channels you wish to use
|
||||
#error ANALOG_MASK not defined
|
||||
#warning ANALOG_MASK not defined - analog subsystem disabled
|
||||
#define ANALOG_MASK 0
|
||||
#endif
|
||||
|
||||
uint8_t adc_running_mask, adc_counter;
|
||||
|
||||
#if ANALOG_MASK & 2
|
||||
#define ANALOG_START 1
|
||||
#define ANALOG_START_MASK 2
|
||||
#elif ANALOG_MASK & 4
|
||||
#define ANALOG_START 2
|
||||
#define ANALOG_START_MASK 4
|
||||
#elif ANALOG_MASK & 8
|
||||
#define ANALOG_START 3
|
||||
#define ANALOG_START_MASK 8
|
||||
#elif ANALOG_MASK & 16
|
||||
#define ANALOG_START 4
|
||||
#define ANALOG_START_MASK 16
|
||||
#elif ANALOG_MASK & 32
|
||||
#define ANALOG_START 5
|
||||
#define ANALOG_START_MASK 32
|
||||
#elif ANALOG_MASK & 64
|
||||
#define ANALOG_START 6
|
||||
#define ANALOG_START_MASK 64
|
||||
#elif ANALOG_MASK & 128
|
||||
#define ANALOG_START 7
|
||||
#define ANALOG_START_MASK 128
|
||||
#else
|
||||
// ANALOG_MASK == 1 or 0, either way defines are the same except they're not used if ANALOG_MASK == 0
|
||||
#define ANALOG_START 0
|
||||
#define ANALOG_START_MASK 1
|
||||
#endif
|
||||
|
||||
volatile uint16_t adc_result[8] __attribute__ ((__section__ (".bss")));
|
||||
|
||||
void analog_init() {
|
||||
|
|
@ -19,21 +45,24 @@ void analog_init() {
|
|||
#elif defined PRR0
|
||||
PRR0 &= ~MASK(PRADC);
|
||||
#endif
|
||||
|
||||
ADMUX = REFERENCE;
|
||||
|
||||
// ADC frequency must be less than 200khz or we lose precision. At 16MHz system clock, we must use the full prescale value of 128 to get an ADC clock of 125khz.
|
||||
ADCSRA = MASK(ADEN) | MASK(ADPS2) | MASK(ADPS1) | MASK(ADPS0);
|
||||
|
||||
adc_counter = 0;
|
||||
adc_running_mask = 1;
|
||||
|
||||
DIDR0 = ANALOG_MASK & 0x1F;
|
||||
AIO0_DDR &= ANALOG_MASK;
|
||||
DIDR0 = ANALOG_MASK & 0x3F;
|
||||
|
||||
// now we start the first conversion and leave the rest to the interrupt
|
||||
ADCSRA |= MASK(ADIE) | MASK(ADSC);
|
||||
#endif
|
||||
#endif /* ANALOG_MASK > 0 */
|
||||
}
|
||||
|
||||
ISR(ADC_vect) {
|
||||
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
|
||||
adc_result[ADMUX & 0x0F] = ADC;
|
||||
// find next channel
|
||||
|
|
@ -41,11 +70,8 @@ ISR(ADC_vect) {
|
|||
adc_counter++;
|
||||
adc_running_mask <<= 1;
|
||||
if (adc_counter == 8) {
|
||||
adc_counter = 0;
|
||||
adc_running_mask = 1;
|
||||
|
||||
// relax interrupt use for analog subsystem- stop after last analog read
|
||||
ADCSRA &= ~MASK(ADIE);
|
||||
adc_counter = ANALOG_START;
|
||||
adc_running_mask = ANALOG_START_MASK;
|
||||
}
|
||||
} while ((adc_running_mask & ANALOG_MASK) == 0);
|
||||
|
||||
|
|
@ -55,15 +81,23 @@ ISR(ADC_vect) {
|
|||
}
|
||||
|
||||
uint16_t analog_read(uint8_t channel) {
|
||||
#if ANALOG_MASK > 0
|
||||
uint16_t r;
|
||||
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
uint8_t sreg;
|
||||
// save interrupt flag
|
||||
sreg = SREG;
|
||||
// disable interrupts
|
||||
cli();
|
||||
|
||||
// atomic 16-bit copy
|
||||
r = adc_result[channel];
|
||||
}
|
||||
|
||||
// re-enable analog read loop so we can get new values
|
||||
ADCSRA |= MASK(ADIE);
|
||||
// restore interrupt flag
|
||||
SREG = sreg;
|
||||
|
||||
return r;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
17
analog_sim.c
17
analog_sim.c
|
|
@ -1,17 +0,0 @@
|
|||
#include "analog.h"
|
||||
#include "simulation.h"
|
||||
|
||||
static bool analog_initialised = false;
|
||||
void analog_init(void)
|
||||
{
|
||||
sim_info("analog_init: not implemented in simulation");
|
||||
analog_initialised = true;
|
||||
}
|
||||
|
||||
uint16_t analog_read(uint8_t channel)
|
||||
{
|
||||
sim_assert(analog_initialised, "analog_init() was not called before analog_read()");
|
||||
sim_assert(sim_interrupts, "interrupts disabled");
|
||||
return 0;
|
||||
}
|
||||
|
||||
10
arduino.h
10
arduino.h
|
|
@ -32,8 +32,10 @@
|
|||
#define READ(IO) _READ(IO)
|
||||
#define WRITE(IO, v) _WRITE(IO, v)
|
||||
#define TOGGLE(IO) _TOGGLE(IO)
|
||||
|
||||
#define SET_INPUT(IO) _SET_INPUT(IO)
|
||||
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
|
||||
|
||||
#define GET_INPUT(IO) _GET_INPUT(IO)
|
||||
#define GET_OUTPUT(IO) _GET_OUTPUT(IO)
|
||||
|
||||
|
|
@ -41,21 +43,19 @@
|
|||
ports and functions
|
||||
|
||||
added as necessary or if I feel like it- not a comprehensive list!
|
||||
|
||||
probably needs some #ifdefs for various chip types
|
||||
*/
|
||||
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
|
||||
#include "arduino_168_328p.h"
|
||||
#endif /* _AVR_ATmega{168,328,328P}__) */
|
||||
#endif /* _AVR_ATmega{168,328,328P}__ */
|
||||
|
||||
#if defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
|
||||
#include "arduino_644.h"
|
||||
#endif
|
||||
#endif /* _AVR_ATmega{644,644P,644PA}__ */
|
||||
|
||||
#if defined (__AVR_ATmega1280__)
|
||||
#include "arduino_1280.h"
|
||||
#endif /* __AVR_ATmega1280__) */
|
||||
#endif /* __AVR_ATmega1280__ */
|
||||
|
||||
#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
|
||||
|
|
|
|||
366
arduino_1280.h
366
arduino_1280.h
|
|
@ -29,7 +29,8 @@
|
|||
#define OC5B DIO45
|
||||
#define OC5C DIO44
|
||||
|
||||
// #define ICP1 NULL /* not brought out on the Arduino Mega, remove line as not used ?? */
|
||||
// change for your board
|
||||
#define DEBUG_LED DIO21
|
||||
|
||||
/*
|
||||
pins
|
||||
|
|
@ -383,3 +384,366 @@ pins
|
|||
#define AIO15_RPORT PINK
|
||||
#define AIO15_WPORT PORTK
|
||||
#define AIO15_DDR DDRK
|
||||
|
||||
#define PA0_PIN PINA0
|
||||
#define PA0_RPORT PINA
|
||||
#define PA0_WPORT PORTA
|
||||
#define PA0_DDR DDRA
|
||||
#define PA1_PIN PINA1
|
||||
#define PA1_RPORT PINA
|
||||
#define PA1_WPORT PORTA
|
||||
#define PA1_DDR DDRA
|
||||
#define PA2_PIN PINA2
|
||||
#define PA2_RPORT PINA
|
||||
#define PA2_WPORT PORTA
|
||||
#define PA2_DDR DDRA
|
||||
#define PA3_PIN PINA3
|
||||
#define PA3_RPORT PINA
|
||||
#define PA3_WPORT PORTA
|
||||
#define PA3_DDR DDRA
|
||||
#define PA4_PIN PINA4
|
||||
#define PA4_RPORT PINA
|
||||
#define PA4_WPORT PORTA
|
||||
#define PA4_DDR DDRA
|
||||
#define PA5_PIN PINA5
|
||||
#define PA5_RPORT PINA
|
||||
#define PA5_WPORT PORTA
|
||||
#define PA5_DDR DDRA
|
||||
#define PA6_PIN PINA6
|
||||
#define PA6_RPORT PINA
|
||||
#define PA6_WPORT PORTA
|
||||
#define PA6_DDR DDRA
|
||||
#define PA7_PIN PINA7
|
||||
#define PA7_RPORT PINA
|
||||
#define PA7_WPORT PORTA
|
||||
#define PA7_DDR DDRA
|
||||
|
||||
#define PB0_PIN PINB0
|
||||
#define PB0_RPORT PINB
|
||||
#define PB0_WPORT PORTB
|
||||
#define PB0_DDR DDRB
|
||||
#define PB1_PIN PINB1
|
||||
#define PB1_RPORT PINB
|
||||
#define PB1_WPORT PORTB
|
||||
#define PB1_DDR DDRB
|
||||
#define PB2_PIN PINB2
|
||||
#define PB2_RPORT PINB
|
||||
#define PB2_WPORT PORTB
|
||||
#define PB2_DDR DDRB
|
||||
#define PB3_PIN PINB3
|
||||
#define PB3_RPORT PINB
|
||||
#define PB3_WPORT PORTB
|
||||
#define PB3_DDR DDRB
|
||||
#define PB4_PIN PINB4
|
||||
#define PB4_RPORT PINB
|
||||
#define PB4_WPORT PORTB
|
||||
#define PB4_DDR DDRB
|
||||
#define PB5_PIN PINB5
|
||||
#define PB5_RPORT PINB
|
||||
#define PB5_WPORT PORTB
|
||||
#define PB5_DDR DDRB
|
||||
#define PB6_PIN PINB6
|
||||
#define PB6_RPORT PINB
|
||||
#define PB6_WPORT PORTB
|
||||
#define PB6_DDR DDRB
|
||||
#define PB7_PIN PINB7
|
||||
#define PB7_RPORT PINB
|
||||
#define PB7_WPORT PORTB
|
||||
#define PB7_DDR DDRB
|
||||
|
||||
#define PC0_PIN PINC0
|
||||
#define PC0_RPORT PINC
|
||||
#define PC0_WPORT PORTC
|
||||
#define PC0_DDR DDRC
|
||||
#define PC1_PIN PINC1
|
||||
#define PC1_RPORT PINC
|
||||
#define PC1_WPORT PORTC
|
||||
#define PC1_DDR DDRC
|
||||
#define PC2_PIN PINC2
|
||||
#define PC2_RPORT PINC
|
||||
#define PC2_WPORT PORTC
|
||||
#define PC2_DDR DDRC
|
||||
#define PC3_PIN PINC3
|
||||
#define PC3_RPORT PINC
|
||||
#define PC3_WPORT PORTC
|
||||
#define PC3_DDR DDRC
|
||||
#define PC4_PIN PINC4
|
||||
#define PC4_RPORT PINC
|
||||
#define PC4_WPORT PORTC
|
||||
#define PC4_DDR DDRC
|
||||
#define PC5_PIN PINC5
|
||||
#define PC5_RPORT PINC
|
||||
#define PC5_WPORT PORTC
|
||||
#define PC5_DDR DDRC
|
||||
#define PC6_PIN PINC6
|
||||
#define PC6_RPORT PINC
|
||||
#define PC6_WPORT PORTC
|
||||
#define PC6_DDR DDRC
|
||||
#define PC7_PIN PINC7
|
||||
#define PC7_RPORT PINC
|
||||
#define PC7_WPORT PORTC
|
||||
#define PC7_DDR DDRC
|
||||
|
||||
#define PD0_PIN PIND0
|
||||
#define PD0_RPORT PIND
|
||||
#define PD0_WPORT PORTD
|
||||
#define PD0_DDR DDRD
|
||||
#define PD1_PIN PIND1
|
||||
#define PD1_RPORT PIND
|
||||
#define PD1_WPORT PORTD
|
||||
#define PD1_DDR DDRD
|
||||
#define PD2_PIN PIND2
|
||||
#define PD2_RPORT PIND
|
||||
#define PD2_WPORT PORTD
|
||||
#define PD2_DDR DDRD
|
||||
#define PD3_PIN PIND3
|
||||
#define PD3_RPORT PIND
|
||||
#define PD3_WPORT PORTD
|
||||
#define PD3_DDR DDRD
|
||||
#define PD4_PIN PIND4
|
||||
#define PD4_RPORT PIND
|
||||
#define PD4_WPORT PORTD
|
||||
#define PD4_DDR DDRD
|
||||
#define PD5_PIN PIND5
|
||||
#define PD5_RPORT PIND
|
||||
#define PD5_WPORT PORTD
|
||||
#define PD5_DDR DDRD
|
||||
#define PD6_PIN PIND6
|
||||
#define PD6_RPORT PIND
|
||||
#define PD6_WPORT PORTD
|
||||
#define PD6_DDR DDRD
|
||||
#define PD7_PIN PIND7
|
||||
#define PD7_RPORT PIND
|
||||
#define PD7_WPORT PORTD
|
||||
#define PD7_DDR DDRD
|
||||
|
||||
#define PE0_PIN PINE0
|
||||
#define PE0_RPORT PINE
|
||||
#define PE0_WPORT PORTE
|
||||
#define PE0_DDR DDRE
|
||||
#define PE1_PIN PINE1
|
||||
#define PE1_RPORT PINE
|
||||
#define PE1_WPORT PORTE
|
||||
#define PE1_DDR DDRE
|
||||
#define PE2_PIN PINE2
|
||||
#define PE2_RPORT PINE
|
||||
#define PE2_WPORT PORTE
|
||||
#define PE2_DDR DDRE
|
||||
#define PE3_PIN PINE3
|
||||
#define PE3_RPORT PINE
|
||||
#define PE3_WPORT PORTE
|
||||
#define PE3_DDR DDRE
|
||||
#define PE4_PIN PINE4
|
||||
#define PE4_RPORT PINE
|
||||
#define PE4_WPORT PORTE
|
||||
#define PE4_DDR DDRE
|
||||
#define PE5_PIN PINE5
|
||||
#define PE5_RPORT PINE
|
||||
#define PE5_WPORT PORTE
|
||||
#define PE5_DDR DDRE
|
||||
#define PE6_PIN PINE6
|
||||
#define PE6_RPORT PINE
|
||||
#define PE6_WPORT PORTE
|
||||
#define PE6_DDR DDRE
|
||||
#define PE7_PIN PINE7
|
||||
#define PE7_RPORT PINE
|
||||
#define PE7_WPORT PORTE
|
||||
#define PE7_DDR DDRE
|
||||
|
||||
#define PF0_PIN PINF0
|
||||
#define PF0_RPORT PINF
|
||||
#define PF0_WPORT PORTF
|
||||
#define PF0_DDR DDRF
|
||||
#define PF1_PIN PINF1
|
||||
#define PF1_RPORT PINF
|
||||
#define PF1_WPORT PORTF
|
||||
#define PF1_DDR DDRF
|
||||
#define PF2_PIN PINF2
|
||||
#define PF2_RPORT PINF
|
||||
#define PF2_WPORT PORTF
|
||||
#define PF2_DDR DDRF
|
||||
#define PF3_PIN PINF3
|
||||
#define PF3_RPORT PINF
|
||||
#define PF3_WPORT PORTF
|
||||
#define PF3_DDR DDRF
|
||||
#define PF4_PIN PINF4
|
||||
#define PF4_RPORT PINF
|
||||
#define PF4_WPORT PORTF
|
||||
#define PF4_DDR DDRF
|
||||
#define PF5_PIN PINF5
|
||||
#define PF5_RPORT PINF
|
||||
#define PF5_WPORT PORTF
|
||||
#define PF5_DDR DDRF
|
||||
#define PF6_PIN PINF6
|
||||
#define PF6_RPORT PINF
|
||||
#define PF6_WPORT PORTF
|
||||
#define PF6_DDR DDRF
|
||||
#define PF7_PIN PINF7
|
||||
#define PF7_RPORT PINF
|
||||
#define PF7_WPORT PORTF
|
||||
#define PF7_DDR DDRF
|
||||
|
||||
#define PG0_PIN PING0
|
||||
#define PG0_RPORT PING
|
||||
#define PG0_WPORT PORTG
|
||||
#define PG0_DDR DDRG
|
||||
#define PG1_PIN PING1
|
||||
#define PG1_RPORT PING
|
||||
#define PG1_WPORT PORTG
|
||||
#define PG1_DDR DDRG
|
||||
#define PG2_PIN PING2
|
||||
#define PG2_RPORT PING
|
||||
#define PG2_WPORT PORTG
|
||||
#define PG2_DDR DDRG
|
||||
#define PG3_PIN PING3
|
||||
#define PG3_RPORT PING
|
||||
#define PG3_WPORT PORTG
|
||||
#define PG3_DDR DDRG
|
||||
#define PG4_PIN PING4
|
||||
#define PG4_RPORT PING
|
||||
#define PG4_WPORT PORTG
|
||||
#define PG4_DDR DDRG
|
||||
#define PG5_PIN PING5
|
||||
#define PG5_RPORT PING
|
||||
#define PG5_WPORT PORTG
|
||||
#define PG5_DDR DDRG
|
||||
#define PG6_PIN PING6
|
||||
#define PG6_RPORT PING
|
||||
#define PG6_WPORT PORTG
|
||||
#define PG6_DDR DDRG
|
||||
#define PG7_PIN PING7
|
||||
#define PG7_RPORT PING
|
||||
#define PG7_WPORT PORTG
|
||||
#define PG7_DDR DDRG
|
||||
|
||||
#define PH0_PIN PINH0
|
||||
#define PH0_RPORT PINH
|
||||
#define PH0_WPORT PORTH
|
||||
#define PH0_DDR DDRH
|
||||
#define PH1_PIN PINH1
|
||||
#define PH1_RPORT PINH
|
||||
#define PH1_WPORT PORTH
|
||||
#define PH1_DDR DDRH
|
||||
#define PH2_PIN PINH2
|
||||
#define PH2_RPORT PINH
|
||||
#define PH2_WPORT PORTH
|
||||
#define PH2_DDR DDRH
|
||||
#define PH3_PIN PINH3
|
||||
#define PH3_RPORT PINH
|
||||
#define PH3_WPORT PORTH
|
||||
#define PH3_DDR DDRH
|
||||
#define PH4_PIN PINH4
|
||||
#define PH4_RPORT PINH
|
||||
#define PH4_WPORT PORTH
|
||||
#define PH4_DDR DDRH
|
||||
#define PH5_PIN PINH5
|
||||
#define PH5_RPORT PINH
|
||||
#define PH5_WPORT PORTH
|
||||
#define PH5_DDR DDRH
|
||||
#define PH6_PIN PINH6
|
||||
#define PH6_RPORT PINH
|
||||
#define PH6_WPORT PORTH
|
||||
#define PH6_DDR DDRH
|
||||
#define PH7_PIN PINH7
|
||||
#define PH7_RPORT PINH
|
||||
#define PH7_WPORT PORTH
|
||||
#define PH7_DDR DDRH
|
||||
|
||||
#define PJ0_PIN PINJ0
|
||||
#define PJ0_RPORT PINJ
|
||||
#define PJ0_WPORT PORTJ
|
||||
#define PJ0_DDR DDRJ
|
||||
#define PJ1_PIN PINJ1
|
||||
#define PJ1_RPORT PINJ
|
||||
#define PJ1_WPORT PORTJ
|
||||
#define PJ1_DDR DDRJ
|
||||
#define PJ2_PIN PINJ2
|
||||
#define PJ2_RPORT PINJ
|
||||
#define PJ2_WPORT PORTJ
|
||||
#define PJ2_DDR DDRJ
|
||||
#define PJ3_PIN PINJ3
|
||||
#define PJ3_RPORT PINJ
|
||||
#define PJ3_WPORT PORTJ
|
||||
#define PJ3_DDR DDRJ
|
||||
#define PJ4_PIN PINJ4
|
||||
#define PJ4_RPORT PINJ
|
||||
#define PJ4_WPORT PORTJ
|
||||
#define PJ4_DDR DDRJ
|
||||
#define PJ5_PIN PINJ5
|
||||
#define PJ5_RPORT PINJ
|
||||
#define PJ5_WPORT PORTJ
|
||||
#define PJ5_DDR DDRJ
|
||||
#define PJ6_PIN PINJ6
|
||||
#define PJ6_RPORT PINJ
|
||||
#define PJ6_WPORT PORTJ
|
||||
#define PJ6_DDR DDRJ
|
||||
#define PJ7_PIN PINJ7
|
||||
#define PJ7_RPORT PINJ
|
||||
#define PJ7_WPORT PORTJ
|
||||
#define PJ7_DDR DDRJ
|
||||
|
||||
#define PK0_PIN PINK0
|
||||
#define PK0_RPORT PINK
|
||||
#define PK0_WPORT PORTK
|
||||
#define PK0_DDR DDRK
|
||||
#define PK1_PIN PINK1
|
||||
#define PK1_RPORT PINK
|
||||
#define PK1_WPORT PORTK
|
||||
#define PK1_DDR DDRK
|
||||
#define PK2_PIN PINK2
|
||||
#define PK2_RPORT PINK
|
||||
#define PK2_WPORT PORTK
|
||||
#define PK2_DDR DDRK
|
||||
#define PK3_PIN PINK3
|
||||
#define PK3_RPORT PINK
|
||||
#define PK3_WPORT PORTK
|
||||
#define PK3_DDR DDRK
|
||||
#define PK4_PIN PINK4
|
||||
#define PK4_RPORT PINK
|
||||
#define PK4_WPORT PORTK
|
||||
#define PK4_DDR DDRK
|
||||
#define PK5_PIN PINK5
|
||||
#define PK5_RPORT PINK
|
||||
#define PK5_WPORT PORTK
|
||||
#define PK5_DDR DDRK
|
||||
#define PK6_PIN PINK6
|
||||
#define PK6_RPORT PINK
|
||||
#define PK6_WPORT PORTK
|
||||
#define PK6_DDR DDRK
|
||||
#define PK7_PIN PINK7
|
||||
#define PK7_RPORT PINK
|
||||
#define PK7_WPORT PORTK
|
||||
#define PK7_DDR DDRK
|
||||
|
||||
#define PL0_PIN PINL0
|
||||
#define PL0_RPORT PINL
|
||||
#define PL0_WPORT PORTL
|
||||
#define PL0_DDR DDRL
|
||||
#define PL1_PIN PINL1
|
||||
#define PL1_RPORT PINL
|
||||
#define PL1_WPORT PORTL
|
||||
#define PL1_DDR DDRL
|
||||
#define PL2_PIN PINL2
|
||||
#define PL2_RPORT PINL
|
||||
#define PL2_WPORT PORTL
|
||||
#define PL2_DDR DDRL
|
||||
#define PL3_PIN PINL3
|
||||
#define PL3_RPORT PINL
|
||||
#define PL3_WPORT PORTL
|
||||
#define PL3_DDR DDRL
|
||||
#define PL4_PIN PINL4
|
||||
#define PL4_RPORT PINL
|
||||
#define PL4_WPORT PORTL
|
||||
#define PL4_DDR DDRL
|
||||
#define PL5_PIN PINL5
|
||||
#define PL5_RPORT PINL
|
||||
#define PL5_WPORT PORTL
|
||||
#define PL5_DDR DDRL
|
||||
#define PL6_PIN PINL6
|
||||
#define PL6_RPORT PINL
|
||||
#define PL6_WPORT PORTL
|
||||
#define PL6_DDR DDRL
|
||||
#define PL7_PIN PINL7
|
||||
#define PL7_RPORT PINL
|
||||
#define PL7_WPORT PORTL
|
||||
#define PL7_DDR DDRL
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#define OC2A DIO11
|
||||
#define OC2B DIO3
|
||||
|
||||
#define ICP1 DIO8
|
||||
#define DEBUG_LED AIO5
|
||||
|
||||
/*
|
||||
pins
|
||||
|
|
@ -125,3 +125,102 @@ pins
|
|||
#define AIO5_RPORT PINC
|
||||
#define AIO5_WPORT PORTC
|
||||
#define AIO5_DDR DDRC
|
||||
|
||||
#define PB0_PIN PINB0
|
||||
#define PB0_RPORT PINB
|
||||
#define PB0_WPORT PORTB
|
||||
#define PB0_DDR DDRB
|
||||
#define PB1_PIN PINB1
|
||||
#define PB1_RPORT PINB
|
||||
#define PB1_WPORT PORTB
|
||||
#define PB1_DDR DDRB
|
||||
#define PB2_PIN PINB2
|
||||
#define PB2_RPORT PINB
|
||||
#define PB2_WPORT PORTB
|
||||
#define PB2_DDR DDRB
|
||||
#define PB3_PIN PINB3
|
||||
#define PB3_RPORT PINB
|
||||
#define PB3_WPORT PORTB
|
||||
#define PB3_DDR DDRB
|
||||
#define PB4_PIN PINB4
|
||||
#define PB4_RPORT PINB
|
||||
#define PB4_WPORT PORTB
|
||||
#define PB4_DDR DDRB
|
||||
#define PB5_PIN PINB5
|
||||
#define PB5_RPORT PINB
|
||||
#define PB5_WPORT PORTB
|
||||
#define PB5_DDR DDRB
|
||||
#define PB6_PIN PINB6
|
||||
#define PB6_RPORT PINB
|
||||
#define PB6_WPORT PORTB
|
||||
#define PB6_DDR DDRB
|
||||
#define PB7_PIN PINB7
|
||||
#define PB7_RPORT PINB
|
||||
#define PB7_WPORT PORTB
|
||||
#define PB7_DDR DDRB
|
||||
|
||||
#define PC0_PIN PINC0
|
||||
#define PC0_RPORT PINC
|
||||
#define PC0_WPORT PORTC
|
||||
#define PC0_DDR DDRC
|
||||
#define PC1_PIN PINC1
|
||||
#define PC1_RPORT PINC
|
||||
#define PC1_WPORT PORTC
|
||||
#define PC1_DDR DDRC
|
||||
#define PC2_PIN PINC2
|
||||
#define PC2_RPORT PINC
|
||||
#define PC2_WPORT PORTC
|
||||
#define PC2_DDR DDRC
|
||||
#define PC3_PIN PINC3
|
||||
#define PC3_RPORT PINC
|
||||
#define PC3_WPORT PORTC
|
||||
#define PC3_DDR DDRC
|
||||
#define PC4_PIN PINC4
|
||||
#define PC4_RPORT PINC
|
||||
#define PC4_WPORT PORTC
|
||||
#define PC4_DDR DDRC
|
||||
#define PC5_PIN PINC5
|
||||
#define PC5_RPORT PINC
|
||||
#define PC5_WPORT PORTC
|
||||
#define PC5_DDR DDRC
|
||||
#define PC6_PIN PINC6
|
||||
#define PC6_RPORT PINC
|
||||
#define PC6_WPORT PORTC
|
||||
#define PC6_DDR DDRC
|
||||
#define PC7_PIN PINC7
|
||||
#define PC7_RPORT PINC
|
||||
#define PC7_WPORT PORTC
|
||||
#define PC7_DDR DDRC
|
||||
|
||||
#define PD0_PIN PIND0
|
||||
#define PD0_RPORT PIND
|
||||
#define PD0_WPORT PORTD
|
||||
#define PD0_DDR DDRD
|
||||
#define PD1_PIN PIND1
|
||||
#define PD1_RPORT PIND
|
||||
#define PD1_WPORT PORTD
|
||||
#define PD1_DDR DDRD
|
||||
#define PD2_PIN PIND2
|
||||
#define PD2_RPORT PIND
|
||||
#define PD2_WPORT PORTD
|
||||
#define PD2_DDR DDRD
|
||||
#define PD3_PIN PIND3
|
||||
#define PD3_RPORT PIND
|
||||
#define PD3_WPORT PORTD
|
||||
#define PD3_DDR DDRD
|
||||
#define PD4_PIN PIND4
|
||||
#define PD4_RPORT PIND
|
||||
#define PD4_WPORT PORTD
|
||||
#define PD4_DDR DDRD
|
||||
#define PD5_PIN PIND5
|
||||
#define PD5_RPORT PIND
|
||||
#define PD5_WPORT PORTD
|
||||
#define PD5_DDR DDRD
|
||||
#define PD6_PIN PIND6
|
||||
#define PD6_RPORT PIND
|
||||
#define PD6_WPORT PORTD
|
||||
#define PD6_DDR DDRD
|
||||
#define PD7_PIN PIND7
|
||||
#define PD7_RPORT PIND
|
||||
#define PD7_WPORT PORTD
|
||||
#define PD7_DDR DDRD
|
||||
|
|
|
|||
168
arduino_644.h
168
arduino_644.h
|
|
@ -1,27 +1,31 @@
|
|||
// UART
|
||||
#define RXD DIO0
|
||||
#define TXD DIO1
|
||||
#define RXD DIO8
|
||||
#define TXD DIO9
|
||||
#define RXD0 DIO8
|
||||
#define TXD0 DIO9
|
||||
|
||||
#define RXD1 DIO10
|
||||
#define TXD1 DIO11
|
||||
|
||||
// SPI
|
||||
#define SCK DIO13
|
||||
#define MISO DIO12
|
||||
#define MOSI DIO11
|
||||
#define SS DIO10
|
||||
#define SCK DIO7
|
||||
#define MISO DIO6
|
||||
#define MOSI DIO5
|
||||
#define SS DIO4
|
||||
|
||||
// TWI (I2C)
|
||||
#define SCL AIO5
|
||||
#define SDA AIO4
|
||||
#define SCL DIO16
|
||||
#define SDA DIO17
|
||||
|
||||
// timers and PWM
|
||||
#define OC0A DIO6
|
||||
#define OC0B DIO5
|
||||
#define OC1A DIO9
|
||||
#define OC1B DIO10
|
||||
#define OC2A DIO11
|
||||
#define OC2B DIO3
|
||||
|
||||
#define ICP1 DIO8
|
||||
#define OC0A DIO3
|
||||
#define OC0B DIO4
|
||||
#define OC1A DIO13
|
||||
#define OC1B DIO12
|
||||
#define OC2A DIO15
|
||||
#define OC2B DIO14
|
||||
|
||||
#define DEBUG_LED DIO0
|
||||
/*
|
||||
pins
|
||||
*/
|
||||
|
|
@ -225,3 +229,135 @@ pins
|
|||
#define AIO7_RPORT PINA
|
||||
#define AIO7_WPORT PORTA
|
||||
#define AIO7_DDR DDRA
|
||||
|
||||
#define PA0_PIN PINA0
|
||||
#define PA0_RPORT PINA
|
||||
#define PA0_WPORT PORTA
|
||||
#define PA0_DDR DDRA
|
||||
#define PA1_PIN PINA1
|
||||
#define PA1_RPORT PINA
|
||||
#define PA1_WPORT PORTA
|
||||
#define PA1_DDR DDRA
|
||||
#define PA2_PIN PINA2
|
||||
#define PA2_RPORT PINA
|
||||
#define PA2_WPORT PORTA
|
||||
#define PA2_DDR DDRA
|
||||
#define PA3_PIN PINA3
|
||||
#define PA3_RPORT PINA
|
||||
#define PA3_WPORT PORTA
|
||||
#define PA3_DDR DDRA
|
||||
#define PA4_PIN PINA4
|
||||
#define PA4_RPORT PINA
|
||||
#define PA4_WPORT PORTA
|
||||
#define PA4_DDR DDRA
|
||||
#define PA5_PIN PINA5
|
||||
#define PA5_RPORT PINA
|
||||
#define PA5_WPORT PORTA
|
||||
#define PA5_DDR DDRA
|
||||
#define PA6_PIN PINA6
|
||||
#define PA6_RPORT PINA
|
||||
#define PA6_WPORT PORTA
|
||||
#define PA6_DDR DDRA
|
||||
#define PA7_PIN PINA7
|
||||
#define PA7_RPORT PINA
|
||||
#define PA7_WPORT PORTA
|
||||
#define PA7_DDR DDRA
|
||||
|
||||
#define PB0_PIN PINB0
|
||||
#define PB0_RPORT PINB
|
||||
#define PB0_WPORT PORTB
|
||||
#define PB0_DDR DDRB
|
||||
#define PB1_PIN PINB1
|
||||
#define PB1_RPORT PINB
|
||||
#define PB1_WPORT PORTB
|
||||
#define PB1_DDR DDRB
|
||||
#define PB2_PIN PINB2
|
||||
#define PB2_RPORT PINB
|
||||
#define PB2_WPORT PORTB
|
||||
#define PB2_DDR DDRB
|
||||
#define PB3_PIN PINB3
|
||||
#define PB3_RPORT PINB
|
||||
#define PB3_WPORT PORTB
|
||||
#define PB3_DDR DDRB
|
||||
#define PB4_PIN PINB4
|
||||
#define PB4_RPORT PINB
|
||||
#define PB4_WPORT PORTB
|
||||
#define PB4_DDR DDRB
|
||||
#define PB5_PIN PINB5
|
||||
#define PB5_RPORT PINB
|
||||
#define PB5_WPORT PORTB
|
||||
#define PB5_DDR DDRB
|
||||
#define PB6_PIN PINB6
|
||||
#define PB6_RPORT PINB
|
||||
#define PB6_WPORT PORTB
|
||||
#define PB6_DDR DDRB
|
||||
#define PB7_PIN PINB7
|
||||
#define PB7_RPORT PINB
|
||||
#define PB7_WPORT PORTB
|
||||
#define PB7_DDR DDRB
|
||||
|
||||
#define PC0_PIN PINC0
|
||||
#define PC0_RPORT PINC
|
||||
#define PC0_WPORT PORTC
|
||||
#define PC0_DDR DDRC
|
||||
#define PC1_PIN PINC1
|
||||
#define PC1_RPORT PINC
|
||||
#define PC1_WPORT PORTC
|
||||
#define PC1_DDR DDRC
|
||||
#define PC2_PIN PINC2
|
||||
#define PC2_RPORT PINC
|
||||
#define PC2_WPORT PORTC
|
||||
#define PC2_DDR DDRC
|
||||
#define PC3_PIN PINC3
|
||||
#define PC3_RPORT PINC
|
||||
#define PC3_WPORT PORTC
|
||||
#define PC3_DDR DDRC
|
||||
#define PC4_PIN PINC4
|
||||
#define PC4_RPORT PINC
|
||||
#define PC4_WPORT PORTC
|
||||
#define PC4_DDR DDRC
|
||||
#define PC5_PIN PINC5
|
||||
#define PC5_RPORT PINC
|
||||
#define PC5_WPORT PORTC
|
||||
#define PC5_DDR DDRC
|
||||
#define PC6_PIN PINC6
|
||||
#define PC6_RPORT PINC
|
||||
#define PC6_WPORT PORTC
|
||||
#define PC6_DDR DDRC
|
||||
#define PC7_PIN PINC7
|
||||
#define PC7_RPORT PINC
|
||||
#define PC7_WPORT PORTC
|
||||
#define PC7_DDR DDRC
|
||||
|
||||
#define PD0_PIN PIND0
|
||||
#define PD0_RPORT PIND
|
||||
#define PD0_WPORT PORTD
|
||||
#define PD0_DDR DDRD
|
||||
#define PD1_PIN PIND1
|
||||
#define PD1_RPORT PIND
|
||||
#define PD1_WPORT PORTD
|
||||
#define PD1_DDR DDRD
|
||||
#define PD2_PIN PIND2
|
||||
#define PD2_RPORT PIND
|
||||
#define PD2_WPORT PORTD
|
||||
#define PD2_DDR DDRD
|
||||
#define PD3_PIN PIND3
|
||||
#define PD3_RPORT PIND
|
||||
#define PD3_WPORT PORTD
|
||||
#define PD3_DDR DDRD
|
||||
#define PD4_PIN PIND4
|
||||
#define PD4_RPORT PIND
|
||||
#define PD4_WPORT PORTD
|
||||
#define PD4_DDR DDRD
|
||||
#define PD5_PIN PIND5
|
||||
#define PD5_RPORT PIND
|
||||
#define PD5_WPORT PORTD
|
||||
#define PD5_DDR DDRD
|
||||
#define PD6_PIN PIND6
|
||||
#define PD6_RPORT PIND
|
||||
#define PD6_WPORT PORTD
|
||||
#define PD6_DDR DDRD
|
||||
#define PD7_PIN PIND7
|
||||
#define PD7_RPORT PIND
|
||||
#define PD7_WPORT PORTD
|
||||
#define PD7_DDR DDRD
|
||||
|
|
|
|||
101
clock.c
101
clock.c
|
|
@ -1,74 +1,45 @@
|
|||
/*
|
||||
clock.c
|
||||
|
||||
a system clock with 1ms ticks
|
||||
*/
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include "pinio.h"
|
||||
#include "sersendf.h"
|
||||
#include "dda_queue.h"
|
||||
#include "watchdog.h"
|
||||
#include "temp.h"
|
||||
#include "timer.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// global clock
|
||||
#ifdef GLOBAL_CLOCK
|
||||
volatile uint32_t clock = 0;
|
||||
#endif
|
||||
|
||||
// 1/4 second tick
|
||||
uint8_t clock_counter_250ms = 0;
|
||||
uint8_t clock_counter_1s = 0;
|
||||
volatile uint8_t clock_flag = 0;
|
||||
|
||||
void clock_setup() {
|
||||
// use system clock
|
||||
ASSR = 0;
|
||||
|
||||
// no compare match, CTC mode
|
||||
TCCR2A = MASK(WGM21);
|
||||
// TODO: Timer 2 has higher priority than Timer 1 used for the stepper
|
||||
// interrupts, which is bad. See AVR Reference Manual p. 9:
|
||||
// "The interrupts have priority in accordance
|
||||
// with their Interrupt Vector position. The
|
||||
// lower the Interrupt Vector address, the higher
|
||||
// the priority."
|
||||
// in conjunction with p. 63 (interrupt vector table).
|
||||
|
||||
// 128 prescaler (16MHz / 128 = 125KHz)
|
||||
TCCR2B = MASK(CS22) | MASK(CS20);
|
||||
|
||||
// 125KHz / 125 = 1KHz for a 1ms tick rate
|
||||
OCR2A = 125;
|
||||
|
||||
// interrupt on overflow, when counter reaches OCR2A
|
||||
TIMSK2 |= MASK(OCIE2A);
|
||||
void clock_250ms() {
|
||||
if (steptimeout > (30 * 4)) {
|
||||
power_off();
|
||||
}
|
||||
else
|
||||
steptimeout++;
|
||||
|
||||
ISR(TIMER2_COMPA_vect) {
|
||||
// global clock
|
||||
#ifdef GLOBAL_CLOCK
|
||||
clock++;
|
||||
#endif
|
||||
// 1/4 second tick
|
||||
if (++clock_counter_250ms == 250) {
|
||||
clock_flag |= CLOCK_FLAG_250MS;
|
||||
clock_counter_250ms = 0;
|
||||
if (++clock_counter_1s == 4) {
|
||||
clock_flag |= CLOCK_FLAG_1S;
|
||||
clock_counter_1s = 0;
|
||||
ifclock(CLOCK_FLAG_1S) {
|
||||
if (debug_flags & DEBUG_POSITION) {
|
||||
// current position
|
||||
sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F);
|
||||
|
||||
// target position
|
||||
sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"), movebuffer[mb_tail].endpoint.X, movebuffer[mb_tail].endpoint.Y, movebuffer[mb_tail].endpoint.Z, movebuffer[mb_tail].endpoint.E, movebuffer[mb_tail].endpoint.F);
|
||||
|
||||
// Queue
|
||||
print_queue();
|
||||
}
|
||||
// temperature
|
||||
/* if (temp_get_target())
|
||||
temp_print();*/
|
||||
}
|
||||
}
|
||||
|
||||
void clock_10ms() {
|
||||
// reset watchdog
|
||||
wd_reset();
|
||||
|
||||
temp_tick();
|
||||
|
||||
ifclock(CLOCK_FLAG_250MS) {
|
||||
clock_250ms();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GLOBAL_CLOCK
|
||||
uint32_t clock_read() {
|
||||
uint32_t c;
|
||||
|
||||
cli(); // set atomic
|
||||
c = clock; // copy clock value
|
||||
sei(); // release atomic
|
||||
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
29
clock.h
29
clock.h
|
|
@ -1,32 +1,7 @@
|
|||
#ifndef _CLOCK_H
|
||||
#define _CLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void clock_setup(void) __attribute__ ((cold));
|
||||
|
||||
#ifdef GLOBAL_CLOCK
|
||||
uint32_t clock_read(void);
|
||||
#endif
|
||||
|
||||
extern volatile uint8_t clock_flag;
|
||||
|
||||
#define CLOCK_FLAG_250MS 1
|
||||
#define CLOCK_FLAG_1S 2
|
||||
|
||||
/*
|
||||
ifclock() {}
|
||||
|
||||
so we can do stuff like:
|
||||
ifclock(CLOCK_FLAG_250MS) {
|
||||
report();
|
||||
}
|
||||
|
||||
or:
|
||||
ifclock(CLOCK_FLAG_1S)
|
||||
power_off();
|
||||
*/
|
||||
|
||||
#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F))
|
||||
void clock_250ms(void);
|
||||
void clock_10ms(void);
|
||||
|
||||
#endif /* _CLOCK_H */
|
||||
|
|
|
|||
56
clock_sim.c
56
clock_sim.c
|
|
@ -1,56 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "simulation.h"
|
||||
|
||||
static uint8_t clock_counter_250ms = 0;
|
||||
static uint8_t clock_counter_1s = 0;
|
||||
volatile uint8_t clock_flag = 0;
|
||||
|
||||
static bool clock_initialised = false;
|
||||
#define SIM_CLOCK_SLOWDOWN 50
|
||||
|
||||
static void timer2_isr(int cause, siginfo_t *HowCome, void *ucontext)
|
||||
{
|
||||
if (!sim_interrupts) return;
|
||||
|
||||
sim_interrupts = false;
|
||||
|
||||
// 1/4 second tick
|
||||
if (++clock_counter_250ms == 250 / SIM_CLOCK_SLOWDOWN) {
|
||||
clock_flag |= CLOCK_FLAG_250MS;
|
||||
clock_counter_250ms = 0;
|
||||
if (++clock_counter_1s == 4) {
|
||||
clock_flag |= CLOCK_FLAG_1S;
|
||||
clock_counter_1s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sim_interrupts = true;
|
||||
}
|
||||
|
||||
void clock_setup(void)
|
||||
{
|
||||
struct itimerval itimer;
|
||||
struct sigaction sa;
|
||||
long unsigned int usec = 1000 * SIM_CLOCK_SLOWDOWN;
|
||||
|
||||
sim_info("clock_setup: simulate timer 2 ISR at %luus", usec);
|
||||
sa.sa_sigaction = timer2_isr;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGPROF, &sa, 0)) {
|
||||
sim_error("sigaction");
|
||||
}
|
||||
|
||||
itimer.it_interval.tv_sec = 0;
|
||||
itimer.it_interval.tv_usec = 1000 * SIM_CLOCK_SLOWDOWN;
|
||||
itimer.it_value.tv_sec = 0;
|
||||
itimer.it_value.tv_usec = 1000 * SIM_CLOCK_SLOWDOWN;
|
||||
setitimer(ITIMER_PROF, &itimer, NULL);
|
||||
|
||||
clock_initialised = true;
|
||||
}
|
||||
|
||||
506
config.h.dist
506
config.h.dist
|
|
@ -1,6 +1,48 @@
|
|||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
/*
|
||||
CONTENTS
|
||||
|
||||
1. Mechanical/Hardware
|
||||
2. Acceleration settings
|
||||
3. Pinouts
|
||||
4. Temperature sensors
|
||||
5. Heaters
|
||||
6. Communication options
|
||||
7. Miscellaneous
|
||||
8. Appendix A - PWMable pins and mappings
|
||||
*/
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 1. MECHANICAL/HARDWARE *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
/*
|
||||
Set your microcontroller type in Makefile! atmega168/atmega328p/atmega644p/atmega1280
|
||||
|
||||
If you want to port this to a new chip, start off with arduino.h and see how you go.
|
||||
*/
|
||||
|
||||
/*
|
||||
CPU clock rate
|
||||
*/
|
||||
#ifndef F_CPU
|
||||
#define F_CPU 16000000L
|
||||
#endif
|
||||
|
||||
/*
|
||||
Are you using the official GEN3 motherboard with separate extruder controller?
|
||||
*/
|
||||
#define GEN3
|
||||
|
||||
/*
|
||||
This is the motherboard, as opposed to the extruder. See extruder/ directory for GEN3 extruder firmware
|
||||
*/
|
||||
#define HOST
|
||||
|
||||
/*
|
||||
Values reflecting the gearing of your machine.
|
||||
All numbers are fixed point integers, so no more than 3 digits to the right of the decimal point, please :-)
|
||||
|
|
@ -17,9 +59,12 @@
|
|||
// http://blog.arcol.hu/?p=157 may help with this next one
|
||||
#define STEPS_PER_MM_E 320.000
|
||||
|
||||
|
||||
/*
|
||||
Values depending on the capabilities of your stepper motors and other mechanics.
|
||||
All numbers are integers, no decimals allowed.
|
||||
|
||||
Units are mm/min
|
||||
*/
|
||||
|
||||
// used for G0 rapid moves and as a cap for all other feedrates
|
||||
|
|
@ -34,24 +79,32 @@
|
|||
#define SEARCH_FEEDRATE_Z 50
|
||||
#define SEARCH_FEEDRATE_E 50
|
||||
|
||||
// extruder settings
|
||||
#define TEMP_HYSTERESIS 20
|
||||
#define TEMP_RESIDENCY_TIME 60
|
||||
|
||||
// this is how many steps to suck back the filament by when we stop
|
||||
// this is how many steps to suck back the filament by when we stop. set to zero to disable
|
||||
#define E_STARTSTOP_STEPS 20
|
||||
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 2. ACCELERATION *
|
||||
* *
|
||||
* IMPORTANT: choose only one! These algorithms choose when to step, trying *
|
||||
* to use more than one will have undefined and probably *
|
||||
* disastrous results! *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
acceleration, reprap style.
|
||||
Each movement starts at the speed of the previous command and accelerates or decelerates linearly to reach target speed at the end of the movement.
|
||||
Can also be set in Makefile
|
||||
*/
|
||||
#define ACCELERATION_REPRAP
|
||||
// #define ACCELERATION_REPRAP
|
||||
|
||||
|
||||
/*
|
||||
acceleration and deceleration ramping.
|
||||
Each movement starts at (almost) no speed, linearly accelerates to target speed and decelerates just in time to smoothly stop at the target. alternative to ACCELERATION_REPRAP
|
||||
Can also be set in Makefile
|
||||
*/
|
||||
// #define ACCELERATION_RAMPING
|
||||
|
||||
|
|
@ -60,106 +113,38 @@
|
|||
// valid range = 1 to 8,000,000; 500,000 is a good starting point
|
||||
#define ACCELERATION_STEEPNESS 500000
|
||||
|
||||
#ifdef ACCELERATION_REPRAP
|
||||
#ifdef ACCELERATION_RAMPING
|
||||
#error Cant use ACCELERATION_REPRAP and ACCELERATION_RAMPING together.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// which temperature sensor are you using?
|
||||
// #define TEMP_MAX6675
|
||||
#define TEMP_THERMISTOR
|
||||
// #define TEMP_AD595
|
||||
|
||||
// if you selected thermistor or AD595, what pin is it on?
|
||||
#define TEMP_PIN_CHANNEL AIO0_PIN
|
||||
#define ANALOG_MASK MASK(TEMP_PIN_CHANNEL)
|
||||
|
||||
/*
|
||||
Firmware build options
|
||||
temporal step algorithm
|
||||
This algorithm causes the timer to fire when any axis needs to step, instead of synchronising to the axis with the most steps ala bresenham.
|
||||
|
||||
This algorithm is not a type of acceleration, and I haven't worked out how to integrate acceleration with it.
|
||||
However it does control step timing, so acceleration algorithms seemed appropriate
|
||||
|
||||
The Bresenham algorithm is great for drawing lines, but not so good for steppers - In the case where X steps 3 times to Y's two, Y experiences massive jitter as it steps in sync with X every 2 out of 3 X steps. This is a worst-case, but the problem exists for most non-45/90 degree moves. At higher speeds, the jitter /will/ cause position loss and unnecessary vibration.
|
||||
This algorithm instead calculates when a step occurs on any axis, and sets the timer to that value.
|
||||
|
||||
// TODO: figure out how to add acceleration to this algorithm
|
||||
*/
|
||||
|
||||
/*
|
||||
RepRap Host changes it's communications protocol from time to time and intentionally avoids backwards compatibility. Set this to the date the source code of your Host was fetched from RepRap's repository, which is likely also the build date.
|
||||
See the discussion on the reprap-dev mailing list from 11 Oct. 2010.
|
||||
|
||||
Undefine it for best human readability, set it to an old date for compatibility with hosts before August 2010
|
||||
*/
|
||||
// #define REPRAP_HOST_COMPATIBILITY 19750101
|
||||
#define REPRAP_HOST_COMPATIBILITY 20100806
|
||||
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
|
||||
// #define ACCELERATION_TEMPORAL
|
||||
|
||||
|
||||
// this option makes the step interrupt interruptible.
|
||||
// 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
|
||||
|
||||
/*
|
||||
Xon/Xoff flow control.
|
||||
Redundant when using RepRap Host for sending GCode, but mandatory when sending GCode files with a plain terminal emulator, like GtkTerm (Linux), CoolTerm (Mac) or HyperTerminal (Windows).
|
||||
Can also be set in Makefile
|
||||
*/
|
||||
// #define XONXOFF
|
||||
|
||||
/*
|
||||
move buffer size, in number of moves
|
||||
note that each move takes a fair chunk of ram (69 bytes as of this writing) so don't make the buffer too big - a bigger serial readbuffer may help more than increasing this unless your gcodes are more than 70 characters long on average.
|
||||
however, a larger movebuffer will probably help with lots of short consecutive moves, as each move takes a bunch of math (hence time) to set up so a longer buffer allows more of the math to be done during preceding longer moves
|
||||
*/
|
||||
#define MOVEBUFFER_SIZE 8
|
||||
|
||||
/*
|
||||
FiveD on Arduino implements a watchdog, which has to be reset every 250ms or it will reboot the controller. As rebooting (and letting the GCode sending application trying to continue the build with a then different Home point) is probably even worse than just hanging, and there is no better restore code in place, this is disabled for now.
|
||||
*/
|
||||
// #define USE_WATCHDOG
|
||||
|
||||
/*
|
||||
analog subsystem stuff
|
||||
REFERENCE - which analog reference to use. see analog.h for choices
|
||||
ANALOG_MASK - which analog inputs we will be using, bitmask. eg; #define ANALOG_MASK MASK(AIO0_PIN) | MASK(3) for AIN0 and AIN3
|
||||
*/
|
||||
#define REFERENCE REFERENCE_AREF
|
||||
|
||||
#ifndef ANALOG_MASK
|
||||
#define ANALOG_MASK 0
|
||||
#endif
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 3. PINOUTS *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
/*
|
||||
Machine Pin Definitions
|
||||
|
||||
- make sure to avoid duplicate usage of a pin
|
||||
|
||||
- comment out pins not in use, as this drops the corresponding code and makes operations faster
|
||||
*/
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include "arduino.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
RESERVED pins
|
||||
we NEED these for communication
|
||||
*/
|
||||
|
||||
#define RESERVED_RXD DIO0
|
||||
#define RESERVED_TXD DIO1
|
||||
|
||||
/*
|
||||
these pins are used for the MAX6675
|
||||
Arduino Mega has SPI on different pins
|
||||
*/
|
||||
#if defined (__AVR_ATmega1280__)
|
||||
#define RESERVED_SCK DIO52
|
||||
#define RESERVED_MISO DIO50
|
||||
#define RESERVED_MOSI DIO51
|
||||
#define RESERVED_SS DIO53
|
||||
#else
|
||||
#define RESERVED_SCK DIO13
|
||||
#define RESERVED_MISO DIO12
|
||||
#define RESERVED_MOSI DIO11
|
||||
#define RESERVED_SS DIO10
|
||||
#endif
|
||||
|
||||
#ifndef GEN3
|
||||
/*
|
||||
user defined pins
|
||||
adjust to suit your electronics,
|
||||
|
|
@ -181,85 +166,270 @@
|
|||
#define E_STEP_PIN DIO7
|
||||
#define E_DIR_PIN DIO8
|
||||
|
||||
#define STEPPER_ENABLE_PIN DIO9
|
||||
|
||||
/*
|
||||
* list of PWM-able pins and corresponding timers
|
||||
* timer1 is used for step timing so don't use OC1A/OC1B
|
||||
*
|
||||
* For Arduino Diecimila/Duemilanove/UNO
|
||||
* Don't use OC1A/OC1B (DIO9/DIO10)
|
||||
*
|
||||
* OC0A DIO6
|
||||
* OC0B DIO5
|
||||
* OC1A DIO9
|
||||
* OC1B DIO10
|
||||
* OC2A DIO11
|
||||
* OC2B DIO3
|
||||
*
|
||||
* For Arduino Mega
|
||||
* Don't use OC1A/OC1B (DIO11/DIO12)
|
||||
*
|
||||
* OC0A DIO13
|
||||
* OC0B DIO4
|
||||
* OC1A DIO11
|
||||
* OC1B DIO12
|
||||
* OC2A DIO10
|
||||
* OC2B DIO9
|
||||
* OC3A DIO5
|
||||
* OC3B DIO2
|
||||
* OC3C DIO3
|
||||
* OC4A DIO6
|
||||
* OC4B DIO7
|
||||
* OC4C DIO8
|
||||
* OC5A DIO46
|
||||
* OC5B DIO45
|
||||
* OC5C DIO44
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// comment out the ones you don't have
|
||||
#define HEATER_PIN DIO6
|
||||
#define HEATER_PWM OCR0A
|
||||
|
||||
#define FAN_PIN DIO5
|
||||
#define FAN_PWM OCR0B
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// you shouldn't need to edit anything below this line
|
||||
|
||||
/*
|
||||
fan
|
||||
*/
|
||||
|
||||
#ifdef FAN_PIN
|
||||
#ifdef FAN_PWM
|
||||
#define enable_fan() do { TCCR0A |= MASK(COM0B1); } while (0)
|
||||
#define disable_fan() do { TCCR0A &= ~MASK(COM0B1); } while (0)
|
||||
#define PS_ON_PIN DIO9
|
||||
#else
|
||||
#define enable_fan() WRITE(FAN_PIN, 1)
|
||||
#define disable_fan() WRITE(FAN_PIN, 0);
|
||||
#endif
|
||||
#else
|
||||
#define enable_fan() if (0) {}
|
||||
#define disable_fan() if (0) {}
|
||||
/*
|
||||
this is the official gen3 reprap motherboard pinout
|
||||
*/
|
||||
#define TX_ENABLE_PIN DIO12
|
||||
#define RX_ENABLE_PIN DIO13
|
||||
|
||||
#define X_STEP_PIN DIO15
|
||||
#define X_DIR_PIN DIO18
|
||||
#define X_MIN_PIN DIO20
|
||||
#define X_MAX_PIN DIO21
|
||||
#define X_ENABLE_PIN DIO19
|
||||
|
||||
#define Y_STEP_PIN DIO23
|
||||
#define Y_DIR_PIN DIO22
|
||||
#define Y_MIN_PIN AIO6
|
||||
#define Y_MAX_PIN AIO5
|
||||
#define Y_ENABLE_PIN DIO7
|
||||
|
||||
#define Z_STEP_PIN AIO4
|
||||
#define Z_DIR_PIN AIO3
|
||||
#define Z_MIN_PIN AIO1
|
||||
#define Z_MAX_PIN AIO0
|
||||
#define Z_ENABLE_PIN AIO2
|
||||
|
||||
#define E_STEP_PIN DIO16
|
||||
#define E_DIR_PIN DIO17
|
||||
|
||||
#define SD_CARD_DETECT DIO2
|
||||
#define SD_WRITE_PROTECT DIO3
|
||||
#endif
|
||||
|
||||
/*
|
||||
Stepper Enable (ATX PSU pwr_good signal?)
|
||||
*/
|
||||
|
||||
#ifdef STEPPER_ENABLE_PIN
|
||||
// for connection to stepper driver ENABLE pins (negative asserted)
|
||||
// #define power_on() WRITE(STEPPER_ENABLE_PIN, 0)
|
||||
// #define power_off() WRITE(STEPPER_ENABLE_PIN, 1)
|
||||
// for connection to ATX PSU PWR_ON signal
|
||||
#define power_on() do { WRITE(STEPPER_ENABLE_PIN, 0); SET_OUTPUT(STEPPER_ENABLE_PIN); } while (0)
|
||||
#define power_off() SET_INPUT(STEPPER_ENABLE_PIN)
|
||||
#else
|
||||
#define power_on() if (0) {}
|
||||
#define power_off() if (0) {}
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 4. TEMPERATURE SENSORS *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
/*
|
||||
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
|
||||
#define TEMP_RESIDENCY_TIME 60
|
||||
|
||||
// which temperature sensors are you using? (intercom is the gen3-style separate extruder board)
|
||||
// #define TEMP_MAX6675
|
||||
// #define TEMP_THERMISTOR
|
||||
// #define TEMP_AD595
|
||||
// #define TEMP_PT100
|
||||
#define TEMP_INTERCOM
|
||||
|
||||
// if you selected thermistor or AD595, what pin is it on? (this value only used to fill ANALOG_MASK for you)
|
||||
#define TEMP_PIN_CHANNEL AIO0_PIN
|
||||
|
||||
// ANALOG_MASK is a bitmask of all analog channels used- if you use more than one analog input (more than one temp sensor?), bitwise-or them all together
|
||||
#define ANALOG_MASK MASK(TEMP_PIN_CHANNEL)
|
||||
|
||||
// how many temperature sensors do you have?
|
||||
#define NUM_TEMP_SENSORS 1
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* Fill in the following struct according to your hardware *
|
||||
* *
|
||||
* If your temperature sensor has no associated heater, enter '255' as the *
|
||||
* heater index. Unassociated temperature sensors are still read, but they *
|
||||
* do not affect firmware operation *
|
||||
* *
|
||||
* for GEN3 set temp_type to TT_INTERCOM, temp_pin to 0 and heater index to *
|
||||
* 255 - the extruder manages the heater for us *
|
||||
* *
|
||||
* Types are same as TEMP_ list above- TT_MAX6675, TT_THERMISTOR, TT_AD595, *
|
||||
* TT_PT100, TT_INTERCOM. See list in temp.c. *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
#ifdef TEMP_C
|
||||
struct {
|
||||
uint8_t temp_type;
|
||||
uint8_t temp_pin;
|
||||
|
||||
uint8_t heater_index;
|
||||
} temp_sensors[NUM_TEMP_SENSORS] =
|
||||
{
|
||||
// type pin heater
|
||||
{ TT_INTERCOM, 0, 255 }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 5. HEATERS *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
// number of heaters- for GEN3, set to zero as extruder manages the heater by itself
|
||||
#define NUM_HEATERS 0
|
||||
|
||||
// check if heater responds to changes in target temperature, disable and spit errors if not
|
||||
// #define HEATER_SANITY_CHECK
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* Fill in the following struct according to your hardware *
|
||||
* *
|
||||
* If your heater isn't on a PWM-able pin, set heater_pwm to zero and we'll *
|
||||
* use bang-bang output. Note that PID will still be used *
|
||||
* *
|
||||
* If a heater isn't attached to a temperature sensor above, it can still be *
|
||||
* controlled by host but otherwise is ignored by firmware *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
#ifdef HEATER_C
|
||||
struct {
|
||||
volatile uint8_t *heater_port;
|
||||
uint8_t heater_pin;
|
||||
volatile uint8_t *heater_pwm;
|
||||
} heaters[NUM_HEATERS]/* =
|
||||
{
|
||||
// port pin pwm
|
||||
{ &PORTD, PIND6, &OCR0A },
|
||||
{ &PORTD, PIND5, &OCR0B }
|
||||
}*/;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 6. COMMUNICATION OPTIONS *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
/*
|
||||
RepRap Host changes it's communications protocol from time to time and intentionally avoids backwards compatibility. Set this to the date the source code of your Host was fetched from RepRap's repository, which is likely also the build date.
|
||||
See the discussion on the reprap-dev mailing list from 11 Oct. 2010.
|
||||
|
||||
Undefine it for best human readability, set it to an old date for compatibility with hosts before August 2010
|
||||
*/
|
||||
// #define REPRAP_HOST_COMPATIBILITY 19750101
|
||||
#define REPRAP_HOST_COMPATIBILITY 20100806
|
||||
// #define REPRAP_HOST_COMPATIBILITY <date of next RepRap Host compatibility break>
|
||||
|
||||
/*
|
||||
Xon/Xoff flow control.
|
||||
Redundant when using RepRap Host for sending GCode, but mandatory when sending GCode files with a plain terminal emulator, like GtkTerm (Linux), CoolTerm (Mac) or HyperTerminal (Windows).
|
||||
Can also be set in Makefile
|
||||
*/
|
||||
// #define XONXOFF
|
||||
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 7. MISCELLANEOUS OPTIONS *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
/*
|
||||
DEBUG
|
||||
enables /heaps/ of extra output, and some extra M-codes.
|
||||
WARNING: this WILL break most host-side talkers that expect particular responses from firmware such as reprap host and replicatorG
|
||||
use with serial terminal or other suitable talker only.
|
||||
*/
|
||||
// #define DEBUG
|
||||
|
||||
/*
|
||||
move buffer size, in number of moves
|
||||
note that each move takes a fair chunk of ram (69 bytes as of this writing) so don't make the buffer too big - a bigger serial readbuffer may help more than increasing this unless your gcodes are more than 70 characters long on average.
|
||||
however, a larger movebuffer will probably help with lots of short consecutive moves, as each move takes a bunch of math (hence time) to set up so a longer buffer allows more of the math to be done during preceding longer moves
|
||||
*/
|
||||
#define MOVEBUFFER_SIZE 8
|
||||
|
||||
/*
|
||||
DC extruder
|
||||
If you have a DC motor extruder, configure it as a "heater" above and define this value as the index.
|
||||
*/
|
||||
// #define DC_EXTRUDER 1
|
||||
// #define DC_EXTRUDER_PWM 180
|
||||
|
||||
/*
|
||||
FiveD on Arduino implements a watchdog, which has to be reset every 250ms or it will reboot the controller. As rebooting (and letting the GCode sending application trying to continue the build with a then different Home point) is probably even worse than just hanging, and there is no better restore code in place, this is disabled for now.
|
||||
*/
|
||||
// #define USE_WATCHDOG
|
||||
|
||||
/*
|
||||
analog subsystem stuff
|
||||
REFERENCE - which analog reference to use. see analog.h for choices
|
||||
*/
|
||||
#define REFERENCE REFERENCE_AVCC
|
||||
|
||||
/*
|
||||
this option makes the step interrupt interruptible (nested).
|
||||
this should help immensely with dropped serial characters, but may also make debugging infuriating due to the complexities arising from nested interrupts
|
||||
*/
|
||||
#define STEP_INTERRUPT_INTERRUPTIBLE 1
|
||||
|
||||
/*
|
||||
how often we overflow and update our clock; with F_CPU=16MHz, max is < 4.096ms (TICK_TIME = 65535)
|
||||
*/
|
||||
#define TICK_TIME 2 MS
|
||||
#define TICK_TIME_MS (TICK_TIME / (F_CPU / 1000))
|
||||
|
||||
/*
|
||||
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
|
||||
#define PID_SCALE 1024L
|
||||
|
||||
|
||||
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* 8. APPENDIX A - PWMABLE PINS AND MAPPINGS *
|
||||
* *
|
||||
* *
|
||||
* list of PWM-able pins and corresponding timers *
|
||||
* timer1 is used for step timing so don't use OC1A/OC1B *
|
||||
* they are omitted from this listing for that reason *
|
||||
* *
|
||||
* For the atmega168/328, timer/pin mappings are as follows *
|
||||
* *
|
||||
* OCR0A - PD6 *
|
||||
* OCR0B - PD5 *
|
||||
* OCR2A - PB3 *
|
||||
* OCR2B - PD3 *
|
||||
* *
|
||||
* For the atmega644, timer/pin mappings are as follows *
|
||||
* *
|
||||
* OCR0A - PB3 *
|
||||
* OCR0B - PB4 *
|
||||
* OCR2A - PD7 *
|
||||
* OCR2B - PD6 *
|
||||
* *
|
||||
* For the atmega1280, timer/pin mappings are as follows *
|
||||
* *
|
||||
* OC0A - PB7 *
|
||||
* OC0B - PG5 *
|
||||
* OC2A - PB4 *
|
||||
* OC2B - PH6 *
|
||||
* OC3A - PE3 *
|
||||
* OC3B - PE4 *
|
||||
* OC3C - PE5 *
|
||||
* OC4A - PH3 *
|
||||
* OC4B - PH4 *
|
||||
* OC4C - PH5 *
|
||||
* OC5A - PL3 *
|
||||
* OC5B - PL4 *
|
||||
* OC5C - PL5 *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
#endif /* _CONFIG_H */
|
||||
|
|
|
|||
7
copier.c
7
copier.c
|
|
@ -1,11 +1,12 @@
|
|||
#ifdef COPIER
|
||||
|
||||
#include "copier.h"
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/boot.h>
|
||||
|
||||
#include "arduino.h"
|
||||
#include "timer.h"
|
||||
#include "serial.h"
|
||||
#include "delay.h"
|
||||
|
||||
uint32_t copier_xchange(uint32_t cmd) {
|
||||
uint32_t r = 0, c = cmd;
|
||||
|
|
@ -96,3 +97,5 @@ void copy() {
|
|||
SET_INPUT(SCK);
|
||||
SET_INPUT(COPIER_RESET);
|
||||
}
|
||||
|
||||
#endif /* COPIER */
|
||||
|
|
|
|||
264
dda.c
264
dda.c
|
|
@ -1,10 +1,8 @@
|
|||
#include "dda.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include <stdlib.h>
|
||||
#include <avr/interrupt.h>
|
||||
#endif
|
||||
|
||||
#include "timer.h"
|
||||
#include "serial.h"
|
||||
|
|
@ -12,64 +10,13 @@
|
|||
#include "dda_queue.h"
|
||||
#include "debug.h"
|
||||
#include "sersendf.h"
|
||||
#include "pinio.h"
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
X Stepper
|
||||
*/
|
||||
|
||||
#define _x_step(st) WRITE(X_STEP_PIN, st)
|
||||
#define x_step() _x_step(1);
|
||||
#define x_direction(dir) WRITE(X_DIR_PIN, dir)
|
||||
#define x_min() READ(X_MIN_PIN)
|
||||
#ifdef X_MAX_PIN
|
||||
#define x_max() READ(X_MAX_PIN)
|
||||
#else
|
||||
#define x_max() (0)
|
||||
#ifdef DC_EXTRUDER
|
||||
#include "heater.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
Y Stepper
|
||||
*/
|
||||
|
||||
#define _y_step(st) WRITE(Y_STEP_PIN, st)
|
||||
#define y_step() _y_step(1);
|
||||
#define y_direction(dir) WRITE(Y_DIR_PIN, dir)
|
||||
#define y_min() READ(Y_MIN_PIN)
|
||||
#ifdef Y_MAX_PIN
|
||||
#define y_max() READ(Y_MAX_PIN)
|
||||
#else
|
||||
#define y_max() (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
Z Stepper
|
||||
*/
|
||||
|
||||
#define _z_step(st) WRITE(Z_STEP_PIN, st)
|
||||
#define z_step() _z_step(1);
|
||||
#define z_direction(dir) WRITE(Z_DIR_PIN, dir)
|
||||
#define z_min() READ(Z_MIN_PIN)
|
||||
#ifdef Z_MAX_PIN
|
||||
#define z_max() READ(Z_MAX_PIN)
|
||||
#else
|
||||
#define z_max() (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
Extruder
|
||||
*/
|
||||
|
||||
#define _e_step(st) WRITE(E_STEP_PIN, st)
|
||||
#define e_step() _e_step(1);
|
||||
#define e_direction(dir) WRITE(E_DIR_PIN, dir)
|
||||
|
||||
/*
|
||||
End Step - All Steppers
|
||||
(so we don't have to delay in interrupt context)
|
||||
*/
|
||||
|
||||
#define unstep() do { _x_step(0); _y_step(0); _z_step(0); _e_step(0); } while (0)
|
||||
|
||||
/*
|
||||
Used in distance calculation during DDA setup
|
||||
*/
|
||||
|
|
@ -78,14 +25,6 @@
|
|||
#define UM_PER_STEP_Z 1000L / ((uint32_t) STEPS_PER_MM_Z)
|
||||
#define UM_PER_STEP_E 1000L / ((uint32_t) STEPS_PER_MM_E)
|
||||
|
||||
/*
|
||||
Maths
|
||||
*/
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(v) (((v) >= 0)?(v):(-(v)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
step timeout
|
||||
*/
|
||||
|
|
@ -189,32 +128,18 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
// we end at the passed target
|
||||
memcpy(&(dda->endpoint), target, sizeof(TARGET));
|
||||
|
||||
dda->x_delta = ABS(target->X - startpoint.X);
|
||||
dda->y_delta = ABS(target->Y - startpoint.Y);
|
||||
dda->z_delta = ABS(target->Z - startpoint.Z);
|
||||
dda->e_delta = ABS(target->E - startpoint.E);
|
||||
dda->x_delta = labs(target->X - startpoint.X);
|
||||
dda->y_delta = labs(target->Y - startpoint.Y);
|
||||
dda->z_delta = labs(target->Z - startpoint.Z);
|
||||
dda->e_delta = labs(target->E - startpoint.E);
|
||||
|
||||
dda->x_direction = (target->X >= startpoint.X)?1:0;
|
||||
dda->y_direction = (target->Y >= startpoint.Y)?1:0;
|
||||
dda->z_direction = (target->Z >= startpoint.Z)?1:0;
|
||||
dda->e_direction = (target->E >= startpoint.E)?1:0;
|
||||
|
||||
if (debug_flags & DEBUG_DDA) {
|
||||
if (dda->x_direction == 0)
|
||||
serial_writechar('-');
|
||||
serwrite_uint32(dda->x_delta); serial_writechar(',');
|
||||
if (dda->y_direction == 0)
|
||||
serial_writechar('-');
|
||||
serwrite_uint32(dda->y_delta); serial_writechar(',');
|
||||
if (dda->z_direction == 0)
|
||||
serial_writechar('-');
|
||||
serwrite_uint32(dda->z_delta); serial_writechar(',');
|
||||
if (dda->e_direction == 0)
|
||||
serial_writechar('-');
|
||||
serwrite_uint32(dda->e_delta);
|
||||
|
||||
serial_writestr_P(PSTR("] ["));
|
||||
}
|
||||
if (debug_flags & DEBUG_DDA)
|
||||
sersendf_P(PSTR("%ld,%ld,%ld,%ld] ["), target->X - startpoint.X, target->Y - startpoint.Y, target->Z - startpoint.Z, target->E - startpoint.E);
|
||||
|
||||
dda->total_steps = dda->x_delta;
|
||||
if (dda->y_delta > dda->total_steps)
|
||||
|
|
@ -224,9 +149,8 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
if (dda->e_delta > dda->total_steps)
|
||||
dda->total_steps = dda->e_delta;
|
||||
|
||||
if (debug_flags & DEBUG_DDA) {
|
||||
serial_writestr_P(PSTR("ts:")); serwrite_uint32(dda->total_steps);
|
||||
}
|
||||
if (debug_flags & DEBUG_DDA)
|
||||
sersendf_P(PSTR("ts:%lu"), dda->total_steps);
|
||||
|
||||
if (dda->total_steps == 0) {
|
||||
dda->nullmove = 1;
|
||||
|
|
@ -235,9 +159,10 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
// get steppers ready to go
|
||||
steptimeout = 0;
|
||||
power_on();
|
||||
|
||||
dda->x_counter = dda->y_counter = dda->z_counter = dda->e_counter =
|
||||
-(dda->total_steps >> 1);
|
||||
x_enable();
|
||||
y_enable();
|
||||
if (dda->z_delta)
|
||||
z_enable();
|
||||
|
||||
// since it's unusual to combine X, Y and Z changes in a single move on reprap, check if we can use simpler approximations before trying the full 3d approximation.
|
||||
if (dda->z_delta == 0)
|
||||
|
|
@ -250,9 +175,15 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
if (distance < 2)
|
||||
distance = dda->e_delta * UM_PER_STEP_E;
|
||||
|
||||
if (debug_flags & DEBUG_DDA) {
|
||||
serial_writestr_P(PSTR(",ds:")); serwrite_uint32(distance);
|
||||
}
|
||||
if (debug_flags & DEBUG_DDA)
|
||||
sersendf_P(PSTR(",ds:%lu"), distance);
|
||||
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
// bracket part of this equation in an attempt to avoid overflow: 60 * 16MHz * 5mm is >32 bits
|
||||
uint32_t move_duration = distance * (60 * F_CPU / startpoint.F);
|
||||
#else
|
||||
dda->x_counter = dda->y_counter = dda->z_counter = dda->e_counter =
|
||||
-(dda->total_steps >> 1);
|
||||
|
||||
// pre-calculate move speed in millimeter microseconds per step minute for less math in interrupt context
|
||||
// mm (distance) * 60000000 us/min / step (total_steps) = mm.us per step.min
|
||||
|
|
@ -270,19 +201,24 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
// changed distance * 6000 .. * F_CPU / 100000 to
|
||||
// distance * 2400 .. * F_CPU / 40000 so we can move a distance of up to 1800mm without overflowing
|
||||
uint32_t move_duration = ((distance * 2400) / dda->total_steps) * (F_CPU / 40000);
|
||||
#endif
|
||||
|
||||
// similarly, find out how fast we can run our axes.
|
||||
// do this for each axis individually, as the combined speed of two or more axes can be higher than the capabilities of a single one.
|
||||
c_limit = 0;
|
||||
// check X axis
|
||||
c_limit_calc = ( (dda->x_delta * (UM_PER_STEP_X * 2400L)) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_X) << 8;
|
||||
if (c_limit_calc > c_limit)
|
||||
c_limit = c_limit_calc;
|
||||
// check Y axis
|
||||
c_limit_calc = ( (dda->y_delta * (UM_PER_STEP_Y * 2400L)) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Y) << 8;
|
||||
if (c_limit_calc > c_limit)
|
||||
c_limit = c_limit_calc;
|
||||
// check Z axis
|
||||
c_limit_calc = ( (dda->z_delta * (UM_PER_STEP_Z * 2400L)) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_Z) << 8;
|
||||
if (c_limit_calc > c_limit)
|
||||
c_limit = c_limit_calc;
|
||||
// check E axis
|
||||
c_limit_calc = ( (dda->e_delta * (UM_PER_STEP_E * 2400L)) / dda->total_steps * (F_CPU / 40000) / MAXIMUM_FEEDRATE_E) << 8;
|
||||
if (c_limit_calc > c_limit)
|
||||
c_limit = c_limit_calc;
|
||||
|
|
@ -296,10 +232,8 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
if (dda->end_c < c_limit)
|
||||
dda->end_c = c_limit;
|
||||
|
||||
if (debug_flags & DEBUG_DDA) {
|
||||
serial_writestr_P(PSTR(",md:")); serwrite_uint32(move_duration);
|
||||
serial_writestr_P(PSTR(",c:")); serwrite_uint32(dda->c >> 8);
|
||||
}
|
||||
if (debug_flags & DEBUG_DDA)
|
||||
sersendf_P(PSTR(",md:%lu,c:%lu"), move_duration, dda->c >> 8);
|
||||
|
||||
if (dda->c != dda->end_c) {
|
||||
uint32_t stF = startpoint.F / 4;
|
||||
|
|
@ -335,17 +269,8 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
dda->n = (((int32_t) ssq / dsq) * (int32_t) dda->total_steps) + 1;
|
||||
}
|
||||
|
||||
if (debug_flags & DEBUG_DDA) {
|
||||
sersendf_P(PSTR("\n{DDA:CA end_c:%lu, n:%ld, md:%lu, ssq:%lu, esq:%lu, dsq:%lu, msbssq:%u, msbtot:%u}\n"),
|
||||
(long unsigned int)dda->end_c >> 8,
|
||||
(long int)dda->n,
|
||||
(long unsigned int)move_duration,
|
||||
(long unsigned int)ssq,
|
||||
(long unsigned int)esq,
|
||||
(long unsigned int)dsq,
|
||||
msb_ssq,
|
||||
msb_tot);
|
||||
}
|
||||
if (debug_flags & DEBUG_DDA)
|
||||
sersendf_P(PSTR("\n{DDA:CA end_c:%lu, n:%ld, md:%lu, ssq:%lu, esq:%lu, dsq:%lu, msbssq:%u, msbtot:%u}\n"), dda->end_c >> 8, dda->n, move_duration, ssq, esq, dsq, msb_ssq, msb_tot);
|
||||
|
||||
dda->accel = 1;
|
||||
}
|
||||
|
|
@ -362,6 +287,21 @@ void dda_create(DDA *dda, TARGET *target) {
|
|||
dda->c_min = c_limit;
|
||||
dda->n = 1;
|
||||
dda->ramp_state = RAMP_UP;
|
||||
#elif defined ACCELERATION_TEMPORAL
|
||||
dda->x_counter = dda->x_step_interval = move_duration / dda->x_delta;
|
||||
dda->y_counter = dda->y_step_interval = move_duration / dda->y_delta;
|
||||
dda->z_counter = dda->z_step_interval = move_duration / dda->z_delta;
|
||||
dda->e_counter = dda->e_step_interval = move_duration / dda->e_delta;
|
||||
|
||||
dda->c = dda->x_step_interval;
|
||||
if (dda->y_step_interval < dda->c)
|
||||
dda->c = dda->y_step_interval;
|
||||
if (dda->z_step_interval < dda->c)
|
||||
dda->c = dda->z_step_interval;
|
||||
if (dda->e_step_interval < dda->c)
|
||||
dda->c = dda->e_step_interval;
|
||||
|
||||
dda->c <<= 8;
|
||||
#else
|
||||
dda->c = (move_duration / target->F) << 8;
|
||||
if (dda->c < c_limit)
|
||||
|
|
@ -390,27 +330,38 @@ void dda_start(DDA *dda) {
|
|||
// keep dda->live = 0
|
||||
}
|
||||
else {
|
||||
if (dda->waitfor_temp) {
|
||||
/* if (dda->waitfor_temp) {
|
||||
#ifndef REPRAP_HOST_COMPATIBILITY
|
||||
serial_writestr_P(PSTR("Waiting for target temp\n"));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
else {*/
|
||||
// ensure steppers are ready to go
|
||||
steptimeout = 0;
|
||||
power_on();
|
||||
x_enable();
|
||||
y_enable();
|
||||
if (dda->z_delta)
|
||||
z_enable();
|
||||
|
||||
// set direction outputs
|
||||
x_direction(dda->x_direction);
|
||||
y_direction(dda->y_direction);
|
||||
z_direction(dda->z_direction);
|
||||
e_direction(dda->e_direction);
|
||||
}
|
||||
|
||||
#ifdef DC_EXTRUDER
|
||||
if (dda->e_delta)
|
||||
heater_set(DC_EXTRUDER, DC_EXTRUDER_PWM);
|
||||
#endif
|
||||
|
||||
// }
|
||||
|
||||
// ensure this dda starts
|
||||
dda->live = 1;
|
||||
|
||||
// set timeout for first step
|
||||
setTimer(dda->c >> 8);
|
||||
enableTimerInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +373,56 @@ void dda_step(DDA *dda) {
|
|||
// called from interrupt context! keep it as simple as possible
|
||||
uint8_t did_step = 0;
|
||||
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
if (dda->x_counter <= 0) {
|
||||
if ((current_position.X != dda->endpoint.X) /* &&
|
||||
(x_max() != dda->x_direction) && (x_min() == dda->x_direction) */) {
|
||||
x_step();
|
||||
if (dda->x_direction)
|
||||
current_position.X++;
|
||||
else
|
||||
current_position.X--;
|
||||
}
|
||||
dda->x_counter += dda->x_step_interval;
|
||||
dda->x_delta--;
|
||||
}
|
||||
if (dda->y_counter <= 0) {
|
||||
if ((current_position.Y != dda->endpoint.Y) /* &&
|
||||
(y_max() != dda->y_direction) && (y_min() == dda->y_direction) */) {
|
||||
y_step();
|
||||
if (dda->y_direction)
|
||||
current_position.Y++;
|
||||
else
|
||||
current_position.Y--;
|
||||
}
|
||||
dda->y_counter += dda->y_step_interval;
|
||||
dda->y_delta--;
|
||||
}
|
||||
if (dda->z_counter <= 0) {
|
||||
if ((current_position.Z != dda->endpoint.Z) /* &&
|
||||
(z_max() != dda->z_direction) && (z_min() == dda->z_direction) */) {
|
||||
z_step();
|
||||
if (dda->z_direction)
|
||||
current_position.Z++;
|
||||
else
|
||||
current_position.Z--;
|
||||
}
|
||||
dda->z_counter += dda->z_step_interval;
|
||||
dda->z_delta--;
|
||||
}
|
||||
if (dda->e_counter <= 0) {
|
||||
if ((current_position.E != dda->endpoint.E) /* &&
|
||||
(e_max() != dda->e_direction) && (e_min() == dda->e_direction) */) {
|
||||
e_step();
|
||||
if (dda->e_direction)
|
||||
current_position.E++;
|
||||
else
|
||||
current_position.E--;
|
||||
}
|
||||
dda->e_counter += dda->e_step_interval;
|
||||
dda->e_delta--;
|
||||
}
|
||||
#else
|
||||
if ((current_position.X != dda->endpoint.X) /* &&
|
||||
(x_max() != dda->x_direction) && (x_min() == dda->x_direction) */) {
|
||||
dda->x_counter -= dda->x_delta;
|
||||
|
|
@ -480,6 +481,7 @@ void dda_step(DDA *dda) {
|
|||
dda->e_counter += dda->total_steps;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if STEP_INTERRUPT_INTERRUPTIBLE
|
||||
// since we have sent steps to all the motors that will be stepping and the rest of this function isn't so time critical,
|
||||
|
|
@ -498,11 +500,9 @@ void dda_step(DDA *dda) {
|
|||
) {
|
||||
dda->c = (int32_t) dda->c - ((int32_t) (dda->c * 2) / dda->n);
|
||||
dda->n += 4;
|
||||
setTimer(dda->c >> 8);
|
||||
}
|
||||
else if (dda->c != dda->end_c) {
|
||||
dda->c = dda->end_c;
|
||||
setTimer(dda->c >> 8);
|
||||
}
|
||||
// else we are already at target speed
|
||||
}
|
||||
|
|
@ -532,11 +532,36 @@ void dda_step(DDA *dda) {
|
|||
dda->ramp_state = RAMP_MAX;
|
||||
dda->ramp_steps = dda->total_steps - dda->step_no;
|
||||
}
|
||||
setTimer(dda->c >> 8);
|
||||
break;
|
||||
}
|
||||
dda->step_no++;
|
||||
#endif
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
dda->c = dda->x_counter;
|
||||
if (dda->y_counter < dda->c)
|
||||
dda->c = dda->y_counter;
|
||||
if (dda->z_counter < dda->c)
|
||||
dda->c = dda->z_counter;
|
||||
if (dda->e_counter < dda->c)
|
||||
dda->c = dda->e_counter;
|
||||
|
||||
if (dda->x_delta)
|
||||
dda->x_counter -= dda->c;
|
||||
if (dda->y_delta)
|
||||
dda->y_counter -= dda->c;
|
||||
if (dda->z_delta)
|
||||
dda->z_counter -= dda->c;
|
||||
if (dda->e_delta)
|
||||
dda->e_counter -= dda->c;
|
||||
if (
|
||||
(dda->x_delta > 0) ||
|
||||
(dda->y_delta > 0) ||
|
||||
(dda->z_delta > 0) ||
|
||||
(dda->e_delta > 0))
|
||||
did_step = 1;
|
||||
|
||||
dda->c <<= 8;
|
||||
#endif
|
||||
|
||||
if (did_step) {
|
||||
// we stepped, reset timeout
|
||||
|
|
@ -552,8 +577,13 @@ void dda_step(DDA *dda) {
|
|||
// linear acceleration code doesn't alter F during a move, so we must update it here
|
||||
// in theory, we *could* update F every step, but that would require a divide in interrupt context which should be avoided if at all possible
|
||||
current_position.F = dda->endpoint.F;
|
||||
#ifdef DC_EXTRUDER
|
||||
heater_set(DC_EXTRUDER, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
setTimer(dda->c >> 8);
|
||||
|
||||
// turn off step outputs, hopefully they've been on long enough by now to register with the drivers
|
||||
// if not, too bad. or insert a (very!) small delay here, or fire up a spare timer or something.
|
||||
// we also hope that we don't step before the drivers register the low- limit maximum speed if you think this is a problem.
|
||||
|
|
|
|||
6
dda.h
6
dda.h
|
|
@ -86,6 +86,12 @@ typedef struct {
|
|||
int32_t n;
|
||||
ramp_state_t ramp_state;
|
||||
#endif
|
||||
#ifdef ACCELERATION_TEMPORAL
|
||||
uint32_t x_step_interval;
|
||||
uint32_t y_step_interval;
|
||||
uint32_t z_step_interval;
|
||||
uint32_t e_step_interval;
|
||||
#endif
|
||||
} DDA;
|
||||
|
||||
/*
|
||||
|
|
|
|||
49
dda_queue.c
49
dda_queue.c
|
|
@ -1,13 +1,7 @@
|
|||
#include "dda_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef SIMULATION
|
||||
#include "simulation.h"
|
||||
#else
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/atomic.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "timer.h"
|
||||
|
|
@ -15,6 +9,8 @@
|
|||
#include "sermsg.h"
|
||||
#include "temp.h"
|
||||
#include "delay.h"
|
||||
#include "sersendf.h"
|
||||
#include "clock.h"
|
||||
|
||||
uint8_t mb_head = 0;
|
||||
uint8_t mb_tail = 0;
|
||||
|
|
@ -36,6 +32,7 @@ void queue_step() {
|
|||
// do our next step
|
||||
if (movebuffer[mb_tail].live) {
|
||||
if (movebuffer[mb_tail].waitfor_temp) {
|
||||
setTimer(movebuffer[mb_tail].c >> 8);
|
||||
if (temp_achieved()) {
|
||||
movebuffer[mb_tail].live = movebuffer[mb_tail].waitfor_temp = 0;
|
||||
serial_writestr_P(PSTR("Temp achieved\n"));
|
||||
|
|
@ -84,7 +81,7 @@ void enqueue(TARGET *t) {
|
|||
mb_head = h;
|
||||
|
||||
// fire up in case we're not running yet
|
||||
if (timerInterruptIsEnabled() == 0)
|
||||
if (movebuffer[mb_tail].live == 0)
|
||||
next_move();
|
||||
}
|
||||
|
||||
|
|
@ -94,29 +91,45 @@ void next_move() {
|
|||
// next item
|
||||
uint8_t t = mb_tail + 1;
|
||||
t &= (MOVEBUFFER_SIZE - 1);
|
||||
if (movebuffer[t].waitfor_temp) {
|
||||
#ifndef REPRAP_HOST_COMPATIBILITY
|
||||
serial_writestr_P(PSTR("Waiting for target temp\n"));
|
||||
#endif
|
||||
movebuffer[t].live = 1;
|
||||
setTimer(movebuffer[t].c >> 8);
|
||||
}
|
||||
else {
|
||||
dda_start(&movebuffer[t]);
|
||||
}
|
||||
mb_tail = t;
|
||||
}
|
||||
else
|
||||
disableTimerInterrupt();
|
||||
setTimer(0);
|
||||
}
|
||||
|
||||
void print_queue() {
|
||||
serial_writechar('Q');
|
||||
serwrite_uint8(mb_tail);
|
||||
serial_writechar('/');
|
||||
serwrite_uint8(mb_head);
|
||||
if (queue_full())
|
||||
serial_writechar('F');
|
||||
if (queue_empty())
|
||||
serial_writechar('E');
|
||||
serial_writechar('\n');
|
||||
sersendf_P(PSTR("Q%d/%d%c\n"), mb_tail, mb_head, (queue_full()?'F':(queue_empty()?'E':' ')));
|
||||
}
|
||||
|
||||
void queue_flush() {
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
// save interrupt flag
|
||||
uint8_t sreg = SREG;
|
||||
|
||||
// disable interrupts
|
||||
cli();
|
||||
|
||||
// flush queue
|
||||
mb_tail = mb_head;
|
||||
movebuffer[mb_head].live = 0;
|
||||
|
||||
// restore interrupt flag
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void queue_wait() {
|
||||
for (;queue_empty() == 0;) {
|
||||
ifclock(CLOCK_FLAG_10MS) {
|
||||
clock_10ms();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,4 +36,7 @@ void print_queue(void);
|
|||
// flush the queue for eg; emergency stop
|
||||
void queue_flush(void);
|
||||
|
||||
// wait for queue to empty
|
||||
void queue_wait(void);
|
||||
|
||||
#endif /* _DDA_QUEUE */
|
||||
|
|
|
|||
2
delay.h
2
delay.h
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define WAITING_DELAY 10 MS
|
||||
|
||||
void delay(uint32_t delay);
|
||||
|
||||
void delay_ms(uint32_t delay);
|
||||
|
|
|
|||
15
delay_sim.c
15
delay_sim.c
|
|
@ -1,15 +0,0 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "delay.h"
|
||||
#include "simulation.h"
|
||||
|
||||
void delay(uint32_t us)
|
||||
{
|
||||
usleep(us);
|
||||
}
|
||||
|
||||
void delay_ms(uint32_t ms)
|
||||
{
|
||||
usleep(ms * 1000);
|
||||
}
|
||||
|
||||
17
func.sh
17
func.sh
|
|
@ -108,14 +108,12 @@ mendel_cmd() {
|
|||
local RSC=0
|
||||
local cmd="$*"
|
||||
echo "$cmd" >&3;
|
||||
while [ "$REPLY" != "OK" ] && [ "$REPLY" != "ok" ]
|
||||
local REPLY=""
|
||||
while ! [[ "$REPLY" =~ ^OK ]] && ! [[ "$REPLY" =~ ^ok ]]
|
||||
do
|
||||
read -u 3
|
||||
if [ "$REPLY" != "OK" ] && [ "$REPLY" != "ok" ]
|
||||
then
|
||||
echo "$REPLY"
|
||||
fi
|
||||
if [[ "$REPLY" =~ ^RESEND ]]
|
||||
echo "${REPLY##ok }"
|
||||
if [[ "$REPLY" =~ ^RESEND ]] || [[ "$REPLY" =~ ^rs ]]
|
||||
then
|
||||
if [ "$RSC" -le 3 ]
|
||||
then
|
||||
|
|
@ -137,11 +135,12 @@ mendel_cmd_hr() {
|
|||
local RSC=0
|
||||
echo "$cmd" >&3
|
||||
echo "S> $cmd"
|
||||
while [ "$REPLY" != "OK" ] && [ "$REPLY" != "ok" ]
|
||||
local REPLY=""
|
||||
while ! [[ "$REPLY" =~ ^OK ]] && ! [[ "$REPLY" =~ ^ok ]]
|
||||
do
|
||||
read -u 3
|
||||
echo "<R $REPLY"
|
||||
if [[ "$REPLY" =~ ^RESEND ]]
|
||||
if [[ "$REPLY" =~ ^RESEND ]] || [[ "$REPLY" =~ ^rs ]]
|
||||
then
|
||||
if [ "$RSC" -le 3 ]
|
||||
then
|
||||
|
|
@ -253,7 +252,7 @@ mendel_readsym_mb() {
|
|||
local mbtail=$(mendel_readsym mb_tail)
|
||||
perl - <<'ENDPERL' -- $val $mbhead $mbtail
|
||||
$i = -1;
|
||||
@a = qw/eX 4 eY 4 eZ 4 eE 4 eF 4 flags 9 dX 12 dY 4 dZ 4 dE 4 cX 12 cY 4 cZ 4 cE 4 ts 12 c 12 ec 4 n 4/;
|
||||
@a = qw/eX 4 eY 4 eZ 4 eE 4 eF 4 flags 9 dX 12 dY 4 dZ 4 dE 4 cX 12 cY 4 cZ 4 cE 4 ts 12 c 12 rs 4 sn 4 cm 4 n 4 rs 1/;
|
||||
$c = 0;
|
||||
$c = 1234567;
|
||||
while (length $ARGV[1]) {
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@
|
|||
/*
|
||||
Switch user friendly values to coding friendly values
|
||||
|
||||
This also affects the possible build volume. We have +-2^31 numbers available and as we internally measure position in steps and use a precision factor of 1000, this translates into a possible range of
|
||||
This also affects the possible build volume. We have +/- 2^31 numbers available and as we internally measure position in steps and use a precision factor of 1000, this translates into a possible range of
|
||||
|
||||
2^31 mm / STEPS_PER_MM_x / 1000
|
||||
|
||||
for each axis. For a M6 threaded rod driven machine and 1/16 microstepping this evaluates to
|
||||
|
||||
2^31 mm / 200 / 1 / 16 / 1000 = 671 mm,
|
||||
2^31 mm / 200 / 16 / 1000 = 671 mm,
|
||||
|
||||
which is about the worst case we have. All other machines have a bigger build volume.
|
||||
*/
|
||||
|
|
@ -60,10 +60,14 @@ int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator)
|
|||
e--;
|
||||
|
||||
// scale factors
|
||||
if (multiplicand != 1)
|
||||
r *= multiplicand;
|
||||
if (denominator != 1)
|
||||
r /= denominator;
|
||||
// if (multiplicand != 1)
|
||||
// r *= multiplicand;
|
||||
// if (denominator != 1)
|
||||
// r /= denominator;
|
||||
|
||||
int32_t rnew1 = r * (multiplicand / denominator)
|
||||
int32_t rnew2 = r * (multiplicand % denominator)
|
||||
r = rnew1 + rnew2;
|
||||
|
||||
// sign
|
||||
if (df->sign)
|
||||
|
|
@ -87,32 +91,6 @@ int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator)
|
|||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
public functions
|
||||
*/
|
||||
|
||||
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f) {
|
||||
TARGET t = startpoint;
|
||||
t.X = x;
|
||||
t.Y = y;
|
||||
t.F = f;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void SpecialMoveZ(int32_t z, uint32_t f) {
|
||||
TARGET t = startpoint;
|
||||
t.Z = z;
|
||||
t.F = f;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void SpecialMoveE(int32_t e, uint32_t f) {
|
||||
TARGET t = startpoint;
|
||||
t.E = e;
|
||||
t.F = f;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Character Received - add it to our command *
|
||||
|
|
@ -192,11 +170,9 @@ void gcode_parse_char(uint8_t c) {
|
|||
// but it takes less code, less memory and loses no precision if we do it here instead
|
||||
if ((next_target.M == 104) || (next_target.M == 109))
|
||||
next_target.S = decfloat_to_int(&read_digit, 4, 1);
|
||||
#ifdef HEATER_PIN
|
||||
// if this is heater PID stuff, multiply by PID_SCALE because we divide by PID_SCALE later on
|
||||
else if ((next_target.M >= 130) && (next_target.M <= 132))
|
||||
next_target.S = decfloat_to_int(&read_digit, PID_SCALE, 1);
|
||||
#endif
|
||||
else
|
||||
next_target.S = decfloat_to_int(&read_digit, 1, 1);
|
||||
if (debug_flags & DEBUG_ECHO)
|
||||
|
|
@ -211,6 +187,11 @@ void gcode_parse_char(uint8_t c) {
|
|||
if (debug_flags & DEBUG_ECHO)
|
||||
serwrite_uint16(next_target.P);
|
||||
break;
|
||||
case 'T':
|
||||
next_target.T = read_digit.mantissa;
|
||||
if (debug_flags & DEBUG_ECHO)
|
||||
serwrite_uint8(next_target.T);
|
||||
break;
|
||||
case 'N':
|
||||
next_target.N = decfloat_to_int(&read_digit, 1, 1);
|
||||
if (debug_flags & DEBUG_ECHO)
|
||||
|
|
@ -272,6 +253,9 @@ void gcode_parse_char(uint8_t c) {
|
|||
case 'P':
|
||||
next_target.seen_P = 1;
|
||||
break;
|
||||
case 'T':
|
||||
next_target.seen_T = 1;
|
||||
break;
|
||||
case 'N':
|
||||
next_target.seen_N = 1;
|
||||
break;
|
||||
|
|
@ -374,8 +358,8 @@ void gcode_parse_char(uint8_t c) {
|
|||
// reset variables
|
||||
next_target.seen_X = next_target.seen_Y = next_target.seen_Z = \
|
||||
next_target.seen_E = next_target.seen_F = next_target.seen_S = \
|
||||
next_target.seen_P = next_target.seen_N = next_target.seen_M = \
|
||||
next_target.seen_checksum = next_target.seen_semi_comment = \
|
||||
next_target.seen_P = next_target.seen_T = next_target.seen_N = \
|
||||
next_target.seen_M = next_target.seen_checksum = next_target.seen_semi_comment = \
|
||||
next_target.seen_parens_comment = next_target.checksum_read = \
|
||||
next_target.checksum_calculated = 0;
|
||||
last_field = 0;
|
||||
|
|
@ -392,13 +376,13 @@ void gcode_parse_char(uint8_t c) {
|
|||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* Request a resend of the current line - used from various places. *
|
||||
* *
|
||||
* Relies on the global variable next_target.N being valid. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
\***************************************************************************/
|
||||
|
||||
void request_resend(void) {
|
||||
serial_writestr_P(PSTR("rs "));
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ typedef struct {
|
|||
|
||||
// this holds all the possible data from a received command
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t seen_G :1;
|
||||
uint8_t seen_M :1;
|
||||
uint8_t seen_X :1;
|
||||
|
|
@ -35,13 +37,16 @@ typedef struct {
|
|||
uint8_t seen_S :1;
|
||||
|
||||
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;
|
||||
};
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
uint8_t G;
|
||||
uint8_t M;
|
||||
|
|
@ -50,6 +55,8 @@ typedef struct {
|
|||
int16_t S;
|
||||
uint16_t P;
|
||||
|
||||
uint8_t T;
|
||||
|
||||
uint32_t N;
|
||||
uint32_t N_expected;
|
||||
|
||||
|
|
@ -63,11 +70,6 @@ extern GCODE_COMMAND next_target;
|
|||
// utility functions
|
||||
int32_t decfloat_to_int(decfloat *df, int32_t multiplicand, int32_t denominator);
|
||||
|
||||
// this is where we construct a move without a gcode command, useful for gcodes which require multiple moves eg; homing
|
||||
void SpecialMoveXY(int32_t x, int32_t y, uint32_t f);
|
||||
void SpecialMoveZ(int32_t z, uint32_t f);
|
||||
void SpecialMoveE(int32_t e, uint32_t f);
|
||||
|
||||
// accept the next character and process it
|
||||
void gcode_parse_char(uint8_t c);
|
||||
|
||||
|
|
|
|||
325
gcode_process.c
325
gcode_process.c
|
|
@ -13,7 +13,53 @@
|
|||
#include "heater.h"
|
||||
#include "timer.h"
|
||||
#include "sersendf.h"
|
||||
#include "pinio.h"
|
||||
#include "debug.h"
|
||||
#include "clock.h"
|
||||
|
||||
// the current tool
|
||||
uint8_t tool;
|
||||
// the tool to be changed when we get an M6
|
||||
uint8_t next_tool;
|
||||
|
||||
|
||||
/*
|
||||
public functions
|
||||
*/
|
||||
|
||||
void zero_x(void) {
|
||||
TARGET t = startpoint;
|
||||
t.X = 0;
|
||||
t.F = SEARCH_FEEDRATE_X;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void zero_y(void) {
|
||||
TARGET t = startpoint;
|
||||
t.Y = 0;
|
||||
t.F = SEARCH_FEEDRATE_X;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void zero_z(void) {
|
||||
TARGET t = startpoint;
|
||||
t.Z = 0;
|
||||
t.F = SEARCH_FEEDRATE_Z;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void zero_e(void) {
|
||||
TARGET t = startpoint;
|
||||
t.E = 0;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
void SpecialMoveE(int32_t e, uint32_t f) {
|
||||
TARGET t = startpoint;
|
||||
t.E = e;
|
||||
t.F = f;
|
||||
enqueue(&t);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
|
|
@ -36,7 +82,12 @@ void process_gcode_command() {
|
|||
// startpoint.E = 0;
|
||||
// moved to dda.c, end of dda_create() and dda_queue.c, next_move()
|
||||
|
||||
if (next_target.seen_T) {
|
||||
next_tool = next_target.T;
|
||||
}
|
||||
|
||||
if (next_target.seen_G) {
|
||||
uint8_t axisSelected = 0;
|
||||
switch (next_target.G) {
|
||||
// G0 - rapid, unsynchronised motion
|
||||
// since it would be a major hassle to force the dda to not synchronise, just provide a fast feedrate and hope it's close enough to what host expects
|
||||
|
|
@ -61,10 +112,14 @@ void process_gcode_command() {
|
|||
// G4 - Dwell
|
||||
case 4:
|
||||
// wait for all moves to complete
|
||||
for (;queue_empty() == 0;)
|
||||
wd_reset();
|
||||
queue_wait();
|
||||
// delay
|
||||
delay_ms(next_target.P);
|
||||
for (;next_target.P > 0;next_target.P--) {
|
||||
ifclock(CLOCK_FLAG_10MS) {
|
||||
clock_10ms();
|
||||
}
|
||||
delay_ms(1);
|
||||
}
|
||||
break;
|
||||
|
||||
// G20 - inches as units
|
||||
|
|
@ -84,61 +139,24 @@ void process_gcode_command() {
|
|||
|
||||
// G28 - go home
|
||||
case 28:
|
||||
/*
|
||||
Home XY first
|
||||
*/
|
||||
// hit endstops, no acceleration- we don't care about skipped steps
|
||||
startpoint.F = MAXIMUM_FEEDRATE_X;
|
||||
SpecialMoveXY(-250L * STEPS_PER_MM_X, -250L * STEPS_PER_MM_Y, MAXIMUM_FEEDRATE_X);
|
||||
startpoint.X = startpoint.Y = 0;
|
||||
queue_wait();
|
||||
|
||||
// move forward a bit
|
||||
SpecialMoveXY(5 * STEPS_PER_MM_X, 5 * STEPS_PER_MM_Y, SEARCH_FEEDRATE_X);
|
||||
|
||||
// move back in to endstops slowly
|
||||
SpecialMoveXY(-20 * STEPS_PER_MM_X, -20 * STEPS_PER_MM_Y, SEARCH_FEEDRATE_X);
|
||||
|
||||
// wait for queue to complete
|
||||
for (;queue_empty() == 0;)
|
||||
wd_reset();
|
||||
|
||||
// this is our home point
|
||||
startpoint.X = startpoint.Y = current_position.X = current_position.Y = 0;
|
||||
|
||||
/*
|
||||
Home Z
|
||||
*/
|
||||
// hit endstop, no acceleration- we don't care about skipped steps
|
||||
startpoint.F = MAXIMUM_FEEDRATE_Z;
|
||||
SpecialMoveZ(-250L * STEPS_PER_MM_Z, MAXIMUM_FEEDRATE_Z);
|
||||
startpoint.Z = 0;
|
||||
|
||||
// move forward a bit
|
||||
SpecialMoveZ(5 * STEPS_PER_MM_Z, SEARCH_FEEDRATE_Z);
|
||||
|
||||
// move back into endstop slowly
|
||||
SpecialMoveZ(-20L * STEPS_PER_MM_Z, SEARCH_FEEDRATE_Z);
|
||||
|
||||
// wait for queue to complete
|
||||
for (;queue_empty() == 0;)
|
||||
wd_reset();
|
||||
|
||||
// this is our home point
|
||||
startpoint.Z = current_position.Z = 0;
|
||||
|
||||
/*
|
||||
Home E
|
||||
*/
|
||||
// extruder only runs one way and we have no "endstop", just set this point as home
|
||||
startpoint.E = current_position.E = 0;
|
||||
|
||||
/*
|
||||
Home F
|
||||
*/
|
||||
|
||||
// F has been left at SEARCH_FEEDRATE_Z by the last move, this is a usable "home"
|
||||
// uncomment the following or substitute if you prefer a different default feedrate
|
||||
// startpoint.F = SEARCH_FEEDRATE_Z
|
||||
if (next_target.seen_X) {
|
||||
zero_x();
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_Y) {
|
||||
zero_y();
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_Z) {
|
||||
zero_z();
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_E) {
|
||||
zero_e();
|
||||
axisSelected = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
|
@ -154,26 +172,66 @@ void process_gcode_command() {
|
|||
|
||||
// G92 - set home
|
||||
case 92:
|
||||
startpoint.X = startpoint.Y = startpoint.Z = startpoint.E =
|
||||
current_position.X = current_position.Y = current_position.Z = current_position.E = 0;
|
||||
startpoint.F =
|
||||
current_position.F = SEARCH_FEEDRATE_Z;
|
||||
// wait for queue to empty
|
||||
queue_wait();
|
||||
|
||||
if (next_target.seen_X) {
|
||||
startpoint.X = current_position.X = next_target.target.X;
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_Y) {
|
||||
startpoint.Y = current_position.Y = next_target.target.Y;
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_Z) {
|
||||
startpoint.Z = current_position.Z = next_target.target.Z;
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (next_target.seen_E) {
|
||||
startpoint.E = current_position.E = next_target.target.E;
|
||||
axisSelected = 1;
|
||||
}
|
||||
if (axisSelected == 0) {
|
||||
startpoint.X = current_position.X =
|
||||
startpoint.Y = current_position.Y =
|
||||
startpoint.Z = current_position.Z =
|
||||
startpoint.E = current_position.E = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
// unknown gcode: spit an error
|
||||
default:
|
||||
serial_writestr_P(PSTR("E: Bad G-code "));
|
||||
serwrite_uint8(next_target.G);
|
||||
serial_writechar('\n');
|
||||
sersendf_P(PSTR("E: Bad G-code %d"), next_target.G);
|
||||
// newline is sent from gcode_parse after we return
|
||||
}
|
||||
}
|
||||
else if (next_target.seen_M) {
|
||||
switch (next_target.M) {
|
||||
// M101- extruder on
|
||||
// M2- program end
|
||||
case 2:
|
||||
timer_stop();
|
||||
queue_flush();
|
||||
x_disable();
|
||||
y_disable();
|
||||
z_disable();
|
||||
power_off();
|
||||
for (;;)
|
||||
wd_reset();
|
||||
break;
|
||||
|
||||
// M6- tool change
|
||||
case 6:
|
||||
tool = next_tool;
|
||||
break;
|
||||
// M3/M101- extruder on
|
||||
case 3:
|
||||
case 101:
|
||||
if (temp_achieved() == 0) {
|
||||
enqueue(NULL);
|
||||
}
|
||||
#ifdef DC_EXTRUDER
|
||||
heater_set(DC_EXTRUDER, DC_EXTRUDER_PWM);
|
||||
#elif E_STARTSTOP_STEPS > 0
|
||||
do {
|
||||
// backup feedrate, move E very quickly then restore feedrate
|
||||
backup_f = startpoint.F;
|
||||
|
|
@ -181,12 +239,17 @@ void process_gcode_command() {
|
|||
SpecialMoveE(E_STARTSTOP_STEPS, MAXIMUM_FEEDRATE_E);
|
||||
startpoint.F = backup_f;
|
||||
} while (0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
// M102- extruder reverse
|
||||
|
||||
// M103- extruder off
|
||||
// M5/M103- extruder off
|
||||
case 5:
|
||||
case 103:
|
||||
#ifdef DC_EXTRUDER
|
||||
heater_set(DC_EXTRUDER, 0);
|
||||
#elif E_STARTSTOP_STEPS > 0
|
||||
do {
|
||||
// backup feedrate, move E very quickly then restore feedrate
|
||||
backup_f = startpoint.F;
|
||||
|
|
@ -194,13 +257,13 @@ void process_gcode_command() {
|
|||
SpecialMoveE(-E_STARTSTOP_STEPS, MAXIMUM_FEEDRATE_E);
|
||||
startpoint.F = backup_f;
|
||||
} while (0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
// M104- set temperature
|
||||
case 104:
|
||||
temp_set(next_target.S);
|
||||
temp_set(next_target.P, next_target.S);
|
||||
if (next_target.S) {
|
||||
enable_heater();
|
||||
power_on();
|
||||
}
|
||||
else {
|
||||
|
|
@ -210,26 +273,28 @@ void process_gcode_command() {
|
|||
|
||||
// M105- get temperature
|
||||
case 105:
|
||||
temp_print();
|
||||
temp_print(next_target.P);
|
||||
break;
|
||||
|
||||
// M106- fan on
|
||||
#ifdef FAN_PIN
|
||||
// M7/M106- fan on
|
||||
#if NUM_HEATERS > 1
|
||||
case 7:
|
||||
case 106:
|
||||
enable_fan();
|
||||
heater_set(1, 255);
|
||||
break;
|
||||
// M107- fan off
|
||||
case 9:
|
||||
case 107:
|
||||
disable_fan();
|
||||
heater_set(1, 0);
|
||||
break;
|
||||
#endif
|
||||
|
||||
// M109- set temp and wait
|
||||
case 109:
|
||||
temp_set(next_target.S);
|
||||
temp_set(next_target.P, next_target.S);
|
||||
if (next_target.S) {
|
||||
enable_heater();
|
||||
power_on();
|
||||
enable_heater();
|
||||
}
|
||||
else {
|
||||
disable_heater();
|
||||
|
|
@ -249,72 +314,67 @@ void process_gcode_command() {
|
|||
#endif
|
||||
// M112- immediate stop
|
||||
case 112:
|
||||
disableTimerInterrupt();
|
||||
timer_stop();
|
||||
queue_flush();
|
||||
power_off();
|
||||
break;
|
||||
// M113- extruder PWM
|
||||
// M114- report XYZEF to host
|
||||
case 114:
|
||||
sersendf_P(PSTR("X:%ld,Y:%ld,Z:%ld,E:%ld,F:%ld\n"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F);
|
||||
sersendf_P(PSTR("X:%ld,Y:%ld,Z:%ld,E:%ld,F:%ld"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F);
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
// M115- capabilities string
|
||||
case 115:
|
||||
serial_writestr_P(PSTR("FIRMWARE_NAME:FiveD_on_Arduino FIRMWARE_URL:http%3A//github.com/triffid/FiveD_on_Arduino/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:1 HEATER_COUNT:1\n"));
|
||||
sersendf_P(PSTR("FIRMWARE_NAME:FiveD_on_Arduino FIRMWARE_URL:http%%3A//github.com/triffid/FiveD_on_Arduino/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:%d TEMP_SENSOR_COUNT:%d HEATER_COUNT:%d"), 1, NUM_TEMP_SENSORS, NUM_HEATERS);
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
|
||||
#ifdef HEATER_PIN
|
||||
#if NUM_HEATERS > 0
|
||||
// M130- heater P factor
|
||||
case 130:
|
||||
if (next_target.seen_S)
|
||||
p_factor = next_target.S;
|
||||
pid_set_p(next_target.P, next_target.S);
|
||||
break;
|
||||
// M131- heater I factor
|
||||
case 131:
|
||||
if (next_target.seen_S)
|
||||
i_factor = next_target.S;
|
||||
pid_set_i(next_target.P, next_target.S);
|
||||
break;
|
||||
// M132- heater D factor
|
||||
case 132:
|
||||
if (next_target.seen_S)
|
||||
d_factor = next_target.S;
|
||||
pid_set_d(next_target.P, next_target.S);
|
||||
break;
|
||||
// M133- heater I limit
|
||||
case 133:
|
||||
if (next_target.seen_S)
|
||||
i_limit = next_target.S;
|
||||
pid_set_i_limit(next_target.P, next_target.S);
|
||||
break;
|
||||
// M134- save PID settings to eeprom
|
||||
case 134:
|
||||
heater_save_settings();
|
||||
break;
|
||||
#endif /* HEATER_PIN */
|
||||
// M135- set heater output
|
||||
case 135:
|
||||
if (next_target.seen_S)
|
||||
heater_set(next_target.P, next_target.S);
|
||||
break;
|
||||
#endif /* NUM_HEATERS > 0 */
|
||||
|
||||
// M190- power on
|
||||
case 190:
|
||||
power_on();
|
||||
#ifdef X_ENABLE_PIN
|
||||
WRITE(X_ENABLE_PIN, 0);
|
||||
#endif
|
||||
#ifdef Y_ENABLE_PIN
|
||||
WRITE(Y_ENABLE_PIN, 0);
|
||||
#endif
|
||||
#ifdef Z_ENABLE_PIN
|
||||
WRITE(Z_ENABLE_PIN, 0);
|
||||
#endif
|
||||
x_enable();
|
||||
y_enable();
|
||||
z_enable();
|
||||
steptimeout = 0;
|
||||
break;
|
||||
// M191- power off
|
||||
case 191:
|
||||
#ifdef X_ENABLE_PIN
|
||||
WRITE(X_ENABLE_PIN, 1);
|
||||
#endif
|
||||
#ifdef Y_ENABLE_PIN
|
||||
WRITE(Y_ENABLE_PIN, 1);
|
||||
#endif
|
||||
#ifdef Z_ENABLE_PIN
|
||||
WRITE(Z_ENABLE_PIN, 1);
|
||||
#endif
|
||||
x_disable();
|
||||
y_disable();
|
||||
z_disable();
|
||||
power_off();
|
||||
break;
|
||||
|
||||
|
|
@ -322,47 +382,25 @@ void process_gcode_command() {
|
|||
// M140- echo off
|
||||
case 140:
|
||||
debug_flags &= ~DEBUG_ECHO;
|
||||
serial_writestr_P(PSTR("Echo off\n"));
|
||||
serial_writestr_P(PSTR("Echo off"));
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
// M141- echo on
|
||||
case 141:
|
||||
debug_flags |= DEBUG_ECHO;
|
||||
serial_writestr_P(PSTR("Echo on\n"));
|
||||
serial_writestr_P(PSTR("Echo on"));
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
|
||||
// DEBUG: return current position
|
||||
// DEBUG: return current position, end position, queue
|
||||
case 250:
|
||||
serial_writestr_P(PSTR("{X:"));
|
||||
serwrite_int32(current_position.X);
|
||||
serial_writestr_P(PSTR(",Y:"));
|
||||
serwrite_int32(current_position.Y);
|
||||
serial_writestr_P(PSTR(",Z:"));
|
||||
serwrite_int32(current_position.Z);
|
||||
serial_writestr_P(PSTR(",E:"));
|
||||
serwrite_int32(current_position.E);
|
||||
serial_writestr_P(PSTR(",F:"));
|
||||
serwrite_int32(current_position.F);
|
||||
serial_writestr_P(PSTR(",c:"));
|
||||
serwrite_uint32(movebuffer[mb_tail].c);
|
||||
serial_writestr_P(PSTR("}\n"));
|
||||
|
||||
serial_writestr_P(PSTR("{X:"));
|
||||
serwrite_int32(movebuffer[mb_tail].endpoint.X);
|
||||
serial_writestr_P(PSTR(",Y:"));
|
||||
serwrite_int32(movebuffer[mb_tail].endpoint.Y);
|
||||
serial_writestr_P(PSTR(",Z:"));
|
||||
serwrite_int32(movebuffer[mb_tail].endpoint.Z);
|
||||
serial_writestr_P(PSTR(",E:"));
|
||||
serwrite_int32(movebuffer[mb_tail].endpoint.E);
|
||||
serial_writestr_P(PSTR(",F:"));
|
||||
serwrite_int32(movebuffer[mb_tail].endpoint.F);
|
||||
serial_writestr_P(PSTR(",c:"));
|
||||
sersendf_P(PSTR("{X:%ld,Y:%ld,Z:%ld,E:%ld,F:%lu,c:%lu}\t{X:%ld,Y:%ld,Z:%ld,E:%ld,F:%lu,c:%lu}\t"), current_position.X, current_position.Y, current_position.Z, current_position.E, current_position.F, movebuffer[mb_tail].c, movebuffer[mb_tail].endpoint.X, movebuffer[mb_tail].endpoint.Y, movebuffer[mb_tail].endpoint.Z, movebuffer[mb_tail].endpoint.E, movebuffer[mb_tail].endpoint.F,
|
||||
#ifdef ACCELERATION_REPRAP
|
||||
serwrite_uint32(movebuffer[mb_tail].end_c);
|
||||
movebuffer[mb_tail].end_c
|
||||
#else
|
||||
serwrite_uint32(movebuffer[mb_tail].c);
|
||||
movebuffer[mb_tail].c
|
||||
#endif
|
||||
serial_writestr_P(PSTR("}\n"));
|
||||
);
|
||||
|
||||
print_queue();
|
||||
break;
|
||||
|
|
@ -375,25 +413,20 @@ void process_gcode_command() {
|
|||
serwrite_hex8(*(volatile uint8_t *)(next_target.S));
|
||||
next_target.S++;
|
||||
}
|
||||
serial_writechar('\n');
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
|
||||
// DEBUG: write arbitrary memory locatiom
|
||||
case 254:
|
||||
serwrite_hex8(next_target.S);
|
||||
serial_writechar(':');
|
||||
serwrite_hex8(*(volatile uint8_t *)(next_target.S));
|
||||
serial_writestr_P(PSTR("->"));
|
||||
serwrite_hex8(next_target.P);
|
||||
serial_writechar('\n');
|
||||
sersendf_P(PSTR("%x:%x->%x"), next_target.S, *(volatile uint8_t *)(next_target.S), next_target.P);
|
||||
(*(volatile uint8_t *)(next_target.S)) = next_target.P;
|
||||
// newline is sent from gcode_parse after we return
|
||||
break;
|
||||
#endif /* DEBUG */
|
||||
// unknown mcode: spit an error
|
||||
default:
|
||||
serial_writestr_P(PSTR("E: Bad M-code "));
|
||||
serwrite_uint8(next_target.M);
|
||||
serial_writechar('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
sersendf_P(PSTR("E: Bad M-code %d"), next_target.M);
|
||||
// newline is sent from gcode_parse after we return
|
||||
} // switch (next_target.M)
|
||||
} // else if (next_target.seen_M)
|
||||
} // process_gcode_command()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,19 @@
|
|||
|
||||
#include "gcode_parse.h"
|
||||
|
||||
// the current tool
|
||||
extern uint8_t tool;
|
||||
// the tool to be changed when we get an M6
|
||||
extern uint8_t next_tool;
|
||||
|
||||
void zero_x(void);
|
||||
void zero_y(void);
|
||||
void zero_z(void);
|
||||
void zero_e(void);
|
||||
|
||||
// this is where we construct a move without a gcode command, useful for gcodes which require multiple moves eg; homing
|
||||
void SpecialMoveE(int32_t e, uint32_t f);
|
||||
|
||||
// when we have a whole line, feed it to this
|
||||
void process_gcode_command(void);
|
||||
|
||||
|
|
|
|||
260
heater.c
260
heater.c
|
|
@ -1,91 +1,151 @@
|
|||
#include "heater.h"
|
||||
|
||||
#ifdef HEATER_PIN
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include <stdlib.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include "arduino.h"
|
||||
#include "debug.h"
|
||||
#ifndef EXTRUDER
|
||||
#include "sersendf.h"
|
||||
#endif
|
||||
|
||||
#include "sersendf.h"
|
||||
#include "debug.h"
|
||||
#define HEATER_C
|
||||
#include "config.h"
|
||||
|
||||
int16_t heater_p = 0;
|
||||
int16_t heater_i = 0;
|
||||
int16_t heater_d = 0;
|
||||
// this struct holds the heater PID factors that are stored in the EEPROM during poweroff
|
||||
struct {
|
||||
int32_t p_factor;
|
||||
int32_t i_factor;
|
||||
int32_t d_factor;
|
||||
int16_t i_limit;
|
||||
} heaters_pid[NUM_HEATERS];
|
||||
|
||||
// this struct holds the runtime heater data- PID integrator history, temperature history, sanity checker
|
||||
struct {
|
||||
int16_t heater_i;
|
||||
|
||||
uint16_t temp_history[TH_COUNT];
|
||||
uint8_t temp_history_pointer;
|
||||
|
||||
#ifdef HEATER_SANITY_CHECK
|
||||
uint16_t sanity_counter;
|
||||
uint16_t sane_temperature;
|
||||
#endif
|
||||
} heaters_runtime[NUM_HEATERS];
|
||||
|
||||
#define DEFAULT_P 8192
|
||||
#define DEFAULT_I 512
|
||||
#define DEFAULT_D -24576
|
||||
#define DEFAULT_D 24576
|
||||
#define DEFAULT_I_LIMIT 384
|
||||
|
||||
int32_t p_factor = 0;
|
||||
int32_t i_factor = 0;
|
||||
int32_t d_factor = 0;
|
||||
int16_t i_limit = 0;
|
||||
// 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;
|
||||
} EE_factor;
|
||||
|
||||
int32_t EEMEM EE_p_factor;
|
||||
int32_t EEMEM EE_i_factor;
|
||||
int32_t EEMEM EE_d_factor;
|
||||
int16_t EEMEM EE_i_limit;
|
||||
|
||||
#define TH_COUNT 8
|
||||
uint16_t temp_history[TH_COUNT] __attribute__ ((__section__ (".bss")));
|
||||
uint8_t th_p = 0;
|
||||
EE_factor EEMEM EE_factors[NUM_HEATERS];
|
||||
|
||||
void heater_init() {
|
||||
p_factor = eeprom_read_dword((uint32_t *) &EE_p_factor);
|
||||
i_factor = eeprom_read_dword((uint32_t *) &EE_i_factor);
|
||||
d_factor = eeprom_read_dword((uint32_t *) &EE_d_factor);
|
||||
i_limit = eeprom_read_word((uint16_t *) &EE_i_limit);
|
||||
|
||||
if ((p_factor == 0) && (i_factor == 0) && (d_factor == 0) && (i_limit == 0)) {
|
||||
p_factor = DEFAULT_P;
|
||||
i_factor = DEFAULT_I;
|
||||
d_factor = DEFAULT_D;
|
||||
i_limit = DEFAULT_I_LIMIT;
|
||||
#if NUM_HEATERS > 0
|
||||
uint8_t i;
|
||||
// setup pins
|
||||
for (i = 0; i < NUM_HEATERS; i++) {
|
||||
*(heaters[i].heater_port) &= ~MASK(heaters[i].heater_pin);
|
||||
// DDR is always 1 address below PORT. ugly code but saves ram and an extra field in heaters[] which will never be used anywhere but here
|
||||
*(heaters[i].heater_port - 1) |= MASK(heaters[i].heater_pin);
|
||||
if (heaters[i].heater_pwm) {
|
||||
*heaters[i].heater_pwm = 0;
|
||||
// this is somewhat ugly too, but switch() won't accept pointers for reasons unknown
|
||||
switch((uint16_t) heaters[i].heater_pwm) {
|
||||
case (uint16_t) &OCR0A:
|
||||
TCCR0A |= MASK(COM0A1);
|
||||
break;
|
||||
case (uint16_t) &OCR0B:
|
||||
TCCR0A |= MASK(COM0B1);
|
||||
break;
|
||||
case (uint16_t) &OCR2A:
|
||||
TCCR2A |= MASK(COM2A1);
|
||||
break;
|
||||
case (uint16_t) &OCR2B:
|
||||
TCCR2A |= MASK(COM2B1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HEATER_SANITY_CHECK
|
||||
// 0 is a "sane" temperature when we're trying to cool down
|
||||
heaters_runtime[i].sane_temperature = 0;
|
||||
#endif
|
||||
|
||||
// read factors from eeprom
|
||||
heaters_pid[i].p_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_p_factor);
|
||||
heaters_pid[i].i_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_i_factor);
|
||||
heaters_pid[i].d_factor = eeprom_read_dword((uint32_t *) &EE_factors[i].EE_d_factor);
|
||||
heaters_pid[i].i_limit = eeprom_read_word((uint16_t *) &EE_factors[i].EE_i_limit);
|
||||
|
||||
if ((heaters_pid[i].p_factor == 0) && (heaters_pid[i].i_factor == 0) && (heaters_pid[i].d_factor == 0) && (heaters_pid[i].i_limit == 0)) {
|
||||
heaters_pid[i].p_factor = DEFAULT_P;
|
||||
heaters_pid[i].i_factor = DEFAULT_I;
|
||||
heaters_pid[i].d_factor = DEFAULT_D;
|
||||
heaters_pid[i].i_limit = DEFAULT_I_LIMIT;
|
||||
}
|
||||
}
|
||||
#endif /* NUM_HEATERS > 0 */
|
||||
}
|
||||
|
||||
void heater_save_settings() {
|
||||
eeprom_write_dword((uint32_t *) &EE_p_factor, p_factor);
|
||||
eeprom_write_dword((uint32_t *) &EE_i_factor, i_factor);
|
||||
eeprom_write_dword((uint32_t *) &EE_d_factor, d_factor);
|
||||
eeprom_write_word((uint16_t *) &EE_i_limit, i_limit);
|
||||
#if NUM_HEATERS > 0
|
||||
uint8_t i;
|
||||
for (i = 0; i < NUM_HEATERS; i++) {
|
||||
eeprom_write_dword((uint32_t *) &EE_factors[i].EE_p_factor, heaters_pid[i].p_factor);
|
||||
eeprom_write_dword((uint32_t *) &EE_factors[i].EE_i_factor, heaters_pid[i].i_factor);
|
||||
eeprom_write_dword((uint32_t *) &EE_factors[i].EE_d_factor, heaters_pid[i].d_factor);
|
||||
eeprom_write_word((uint16_t *) &EE_factors[i].EE_i_limit, heaters_pid[i].i_limit);
|
||||
}
|
||||
#endif /* NUM_HEATERS > 0 */
|
||||
}
|
||||
|
||||
void heater_tick(int16_t current_temp, int16_t target_temp) {
|
||||
void heater_tick(uint8_t h, uint8_t t, uint16_t current_temp, uint16_t target_temp) {
|
||||
#if (NUM_HEATERS > 0) && (NUM_TEMP_SENSORS > 0)
|
||||
int16_t heater_p;
|
||||
int16_t heater_d;
|
||||
uint8_t pid_output;
|
||||
|
||||
int16_t t_error = target_temp - current_temp;
|
||||
|
||||
temp_history[th_p++] = current_temp;
|
||||
th_p &= (TH_COUNT - 1);
|
||||
heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer++] = current_temp;
|
||||
heaters_runtime[h].temp_history_pointer &= (TH_COUNT - 1);
|
||||
|
||||
// PID stuff
|
||||
// proportional
|
||||
heater_p = t_error;
|
||||
|
||||
// integral
|
||||
heater_i += t_error;
|
||||
heaters_runtime[h].heater_i += t_error;
|
||||
// prevent integrator wind-up
|
||||
if (heater_i > i_limit)
|
||||
heater_i = i_limit;
|
||||
else if (heater_i < -i_limit)
|
||||
heater_i = -i_limit;
|
||||
if (heaters_runtime[h].heater_i > heaters_pid[h].i_limit)
|
||||
heaters_runtime[h].heater_i = heaters_pid[h].i_limit;
|
||||
else if (heaters_runtime[h].heater_i < -heaters_pid[h].i_limit)
|
||||
heaters_runtime[h].heater_i = -heaters_pid[h].i_limit;
|
||||
|
||||
// derivative
|
||||
// note: D follows temp rather than error so there's no large derivative when the target changes
|
||||
heater_d = current_temp - temp_history[th_p];
|
||||
heater_d = heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer] - current_temp;
|
||||
|
||||
// combine factors
|
||||
int32_t pid_output_intermed = (
|
||||
(
|
||||
(((int32_t) heater_p) * p_factor) +
|
||||
(((int32_t) heater_i) * i_factor) +
|
||||
(((int32_t) heater_d) * d_factor)
|
||||
(((int32_t) heater_p) * heaters_pid[h].p_factor) +
|
||||
(((int32_t) heaters_runtime[h].heater_i) * heaters_pid[h].i_factor) +
|
||||
(((int32_t) heater_d) * heaters_pid[h].d_factor)
|
||||
) / PID_SCALE
|
||||
);
|
||||
|
||||
// rebase and limit factors
|
||||
uint8_t pid_output;
|
||||
if (pid_output_intermed > 255)
|
||||
pid_output = 255;
|
||||
else if (pid_output_intermed < 0)
|
||||
|
|
@ -93,17 +153,101 @@ void heater_tick(int16_t current_temp, int16_t target_temp) {
|
|||
else
|
||||
pid_output = pid_output_intermed & 0xFF;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (debug_flags & DEBUG_PID)
|
||||
sersendf_P(PSTR("T{E:%d, P:%d * %ld = %ld / I:%d * %ld = %ld / D:%d * %ld = %ld # O: %ld = %u}\n"), t_error, heater_p, p_factor, (int32_t) heater_p * p_factor / PID_SCALE, heater_i, i_factor, (int32_t) heater_i * i_factor / PID_SCALE, heater_d, d_factor, (int32_t) heater_d * d_factor / PID_SCALE, pid_output_intermed, pid_output);
|
||||
|
||||
#ifdef HEATER_PWM
|
||||
HEATER_PWM = pid_output;
|
||||
#else
|
||||
if (pid_output >= 8)
|
||||
enable_heater();
|
||||
else
|
||||
disable_heater();
|
||||
sersendf_P(PSTR("T{E:%d, P:%d * %ld = %ld / I:%d * %ld = %ld / D:%d * %ld = %ld # O: %ld = %u}\n"), t_error, heater_p, heaters_pid[h].p_factor, (int32_t) heater_p * heaters_pid[h].p_factor / PID_SCALE, heaters_runtime[h].heater_i, heaters_pid[h].i_factor, (int32_t) heaters_runtime[h].heater_i * heaters_pid[h].i_factor / PID_SCALE, heater_d, heaters_pid[h].d_factor, (int32_t) heater_d * heaters_pid[h].d_factor / PID_SCALE, pid_output_intermed, pid_output);
|
||||
#endif
|
||||
|
||||
#ifdef HEATER_SANITY_CHECK
|
||||
// check heater sanity
|
||||
// implementation is a moving window with some slow-down to compensate for thermal mass
|
||||
if (target_temp > (current_temp + TEMP_HYSTERESIS)) {
|
||||
// heating
|
||||
if (current_temp > heaters_runtime[h].sane_temperature)
|
||||
// hotter than sane- good since we're heating unless too hot
|
||||
heaters_runtime[h].sane_temperature = current_temp;
|
||||
else {
|
||||
if (heaters_runtime[h].sanity_counter < 40)
|
||||
heaters_runtime[h].sanity_counter++;
|
||||
else {
|
||||
heaters_runtime[h].sanity_counter = 0;
|
||||
// ratchet up expected temp
|
||||
heaters_runtime[h].sane_temperature++;
|
||||
}
|
||||
}
|
||||
// limit to target, so if we overshoot by too much for too long an error is flagged
|
||||
if (heaters_runtime[h].sane_temperature > target_temp)
|
||||
heaters_runtime[h].sane_temperature = target_temp;
|
||||
}
|
||||
else if (target_temp < (current_temp - TEMP_HYSTERESIS)) {
|
||||
// cooling
|
||||
if (current_temp < heaters_runtime[h].sane_temperature)
|
||||
// cooler than sane- good since we're cooling
|
||||
heaters_runtime[h].sane_temperature = current_temp;
|
||||
else {
|
||||
if (heaters_runtime[h].sanity_counter < 125)
|
||||
heaters_runtime[h].sanity_counter++;
|
||||
else {
|
||||
heaters_runtime[h].sanity_counter = 0;
|
||||
// ratchet down expected temp
|
||||
heaters_runtime[h].sane_temperature--;
|
||||
}
|
||||
}
|
||||
// if we're at or below 60 celsius, don't freak out if we can't drop any more.
|
||||
if (current_temp <= 240)
|
||||
heaters_runtime[h].sane_temperature = current_temp;
|
||||
// limit to target, so if we don't cool down for too long an error is flagged
|
||||
else if (heaters_runtime[h].sane_temperature < target_temp)
|
||||
heaters_runtime[h].sane_temperature = target_temp;
|
||||
}
|
||||
// we're within HYSTERESIS of our target
|
||||
else {
|
||||
heaters_runtime[h].sane_temperature = current_temp;
|
||||
heaters_runtime[h].sanity_counter = 0;
|
||||
}
|
||||
|
||||
#endif /* HEATER_PIN */
|
||||
// compare where we're at to where we should be
|
||||
if (labs(current_temp - heaters_runtime[h].sane_temperature) > TEMP_HYSTERESIS) {
|
||||
// no change, or change in wrong direction for a long time- heater is broken!
|
||||
pid_output = 0;
|
||||
sersendf_P(PSTR("!! heater %d or temp sensor %d broken- temp is %d.%dC, target is %d.%dC, didn't reach %d.%dC in %d0 milliseconds\n"), h, t, current_temp >> 2, (current_temp & 3) * 25, target_temp >> 2, (target_temp & 3) * 25, heaters_runtime[h].sane_temperature >> 2, (heaters_runtime[h].sane_temperature & 3) * 25, heaters_runtime[h].sanity_counter);
|
||||
}
|
||||
#endif /* HEATER_SANITY_CHECK */
|
||||
|
||||
heater_set(h, pid_output);
|
||||
#endif /* if NUM_HEATERS > 0 && NUM_TEMP_SENSORS > 0 */
|
||||
}
|
||||
|
||||
void heater_set(uint8_t index, uint8_t value) {
|
||||
#if NUM_HEATERS > 0
|
||||
if (heaters[index].heater_pwm) {
|
||||
*(heaters[index].heater_pwm) = value;
|
||||
#ifdef DEBUG
|
||||
if (debug_flags & DEBUG_PID)
|
||||
sersendf_P(PSTR("PWM{%u = %u}\n"), index, OCR0A);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (value >= 8)
|
||||
*(heaters[index].heater_port) |= MASK(heaters[index].heater_pin);
|
||||
else
|
||||
*(heaters[index].heater_port) &= ~MASK(heaters[index].heater_pin);
|
||||
}
|
||||
#endif /* if NUM_HEATERS > 0 */
|
||||
}
|
||||
|
||||
void pid_set_p(uint8_t index, int32_t p) {
|
||||
heaters_pid[index].p_factor = p;
|
||||
}
|
||||
|
||||
void pid_set_i(uint8_t index, int32_t i) {
|
||||
heaters_pid[index].i_factor = i;
|
||||
}
|
||||
|
||||
void pid_set_d(uint8_t index, int32_t d) {
|
||||
heaters_pid[index].d_factor = d;
|
||||
}
|
||||
|
||||
void pid_set_i_limit(uint8_t index, int32_t i_limit) {
|
||||
heaters_pid[index].i_limit = i_limit;
|
||||
}
|
||||
|
|
|
|||
39
heater.h
39
heater.h
|
|
@ -1,41 +1,20 @@
|
|||
#ifndef _HEATER_H
|
||||
#define _HEATER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "simulation.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef HEATER_PIN
|
||||
|
||||
#ifdef HEATER_PWM
|
||||
#define enable_heater() do { TCCR0A |= MASK(COM0A1); } while (0)
|
||||
#define disable_heater() do { TCCR0A &= ~MASK(COM0A1); } while (0)
|
||||
#else
|
||||
#define enable_heater() WRITE(HEATER_PIN, 1)
|
||||
#define disable_heater() WRITE(HEATER_PIN, 0)
|
||||
#endif
|
||||
|
||||
// extruder heater PID factors
|
||||
// google "PID without a PHD" if you don't understand this PID stuff
|
||||
extern int32_t p_factor;
|
||||
extern int32_t i_factor;
|
||||
extern int32_t d_factor;
|
||||
extern int16_t i_limit;
|
||||
|
||||
#define PID_SCALE 1024L
|
||||
#define I_LIMIT 4000
|
||||
#define enable_heater() heater_set(0, 64)
|
||||
#define disable_heater() heater_set(0, 0)
|
||||
|
||||
void heater_init(void);
|
||||
void heater_save_settings(void);
|
||||
void heater_tick(int16_t current_temp, int16_t target_temp);
|
||||
|
||||
#else /* HEATER_PIN */
|
||||
void heater_set(uint8_t index, uint8_t value);
|
||||
void heater_tick(uint8_t h, uint8_t t, uint16_t current_temp, uint16_t target_temp);
|
||||
|
||||
// if there is no heater pin, there is no heater
|
||||
#define enable_heater() /* empty */
|
||||
#define disable_heater() /* empty */
|
||||
#define heater_init() /* empty */
|
||||
#define heater_save_settings() /* empty */
|
||||
#define heater_tick(p1, p2) /* empty */
|
||||
void pid_set_p(uint8_t index, int32_t p);
|
||||
void pid_set_i(uint8_t index, int32_t i);
|
||||
void pid_set_d(uint8_t index, int32_t d);
|
||||
void pid_set_i_limit(uint8_t index, int32_t i_limit);
|
||||
|
||||
#endif /* HEATER_PIN */
|
||||
#endif /* _HEATER_H */
|
||||
|
|
|
|||
130
mendel.c
130
mendel.c
|
|
@ -1,16 +1,15 @@
|
|||
#ifndef SIMULATION
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "fuses.h"
|
||||
|
||||
#include "serial.h"
|
||||
#include "dda_queue.h"
|
||||
#include "dda.h"
|
||||
#include "gcode_parse.h"
|
||||
#include "timer.h"
|
||||
#include "clock.h"
|
||||
#include "temp.h"
|
||||
#include "sermsg.h"
|
||||
#include "watchdog.h"
|
||||
|
|
@ -18,17 +17,19 @@
|
|||
#include "sersendf.h"
|
||||
#include "heater.h"
|
||||
#include "analog.h"
|
||||
#include "simulation.h"
|
||||
#include "pinio.h"
|
||||
#include "arduino.h"
|
||||
#include "clock.h"
|
||||
|
||||
void io_init(void) {
|
||||
// disable modules we don't use
|
||||
#ifdef PRR
|
||||
PRR = MASK(PRTWI) | MASK(PRADC) | MASK(PRSPI);
|
||||
#endif
|
||||
#ifdef PRR0
|
||||
#elif defined PRR0
|
||||
PRR0 = MASK(PRTWI) | MASK(PRADC) | MASK(PRSPI);
|
||||
#ifdef PRR1
|
||||
PRR1 = 0xFF;
|
||||
// don't use USART2 or USART3- leave USART1 for GEN3 and derivatives
|
||||
PRR1 = MASK(PRUSART3) | MASK(PRUSART2);
|
||||
#endif
|
||||
#endif
|
||||
ACSR = MASK(ACD);
|
||||
|
|
@ -37,33 +38,71 @@ void io_init(void) {
|
|||
WRITE(X_STEP_PIN, 0); SET_OUTPUT(X_STEP_PIN);
|
||||
WRITE(X_DIR_PIN, 0); SET_OUTPUT(X_DIR_PIN);
|
||||
WRITE(X_MIN_PIN, 1); SET_INPUT(X_MIN_PIN);
|
||||
#ifdef X_MAX_PIN
|
||||
WRITE(X_MAX_PIN, 1); SET_INPUT(X_MAX_PIN);
|
||||
#endif
|
||||
#ifdef X_ENABLE_PIN
|
||||
WRITE(X_ENABLE_PIN, 1); SET_OUTPUT(X_ENABLE_PIN);
|
||||
#endif
|
||||
|
||||
WRITE(Y_STEP_PIN, 0); SET_OUTPUT(Y_STEP_PIN);
|
||||
WRITE(Y_DIR_PIN, 0); SET_OUTPUT(Y_DIR_PIN);
|
||||
WRITE(Y_MIN_PIN, 1); SET_INPUT(Y_MIN_PIN);
|
||||
#ifdef Y_MAX_PIN
|
||||
WRITE(Y_MAX_PIN, 1); SET_INPUT(Y_MAX_PIN);
|
||||
#endif
|
||||
#ifdef Y_ENABLE_PIN
|
||||
WRITE(Y_ENABLE_PIN, 1); SET_OUTPUT(Y_ENABLE_PIN);
|
||||
#endif
|
||||
|
||||
WRITE(Z_STEP_PIN, 0); SET_OUTPUT(Z_STEP_PIN);
|
||||
WRITE(Z_DIR_PIN, 0); SET_OUTPUT(Z_DIR_PIN);
|
||||
WRITE(Z_MIN_PIN, 1); SET_INPUT(Z_MIN_PIN);
|
||||
#ifdef Z_MAX_PIN
|
||||
WRITE(Z_MAX_PIN, 1); SET_INPUT(Z_MAX_PIN);
|
||||
#endif
|
||||
#ifdef Z_ENABLE_PIN
|
||||
WRITE(Z_ENABLE_PIN, 1); SET_OUTPUT(Z_ENABLE_PIN);
|
||||
#endif
|
||||
|
||||
WRITE(E_STEP_PIN, 0); SET_OUTPUT(E_STEP_PIN);
|
||||
WRITE(E_DIR_PIN, 0); SET_OUTPUT(E_DIR_PIN);
|
||||
|
||||
#ifdef HEATER_PIN
|
||||
WRITE(HEATER_PIN, 0); SET_OUTPUT(HEATER_PIN);
|
||||
#endif
|
||||
|
||||
#ifdef FAN_PIN
|
||||
WRITE(FAN_PIN, 0); SET_OUTPUT(FAN_PIN);
|
||||
#endif
|
||||
|
||||
#if defined(HEATER_PWM) || defined(FAN_PWM)
|
||||
// setup PWM timer: fast PWM, no prescaler
|
||||
// setup PWM timers: fast PWM, no prescaler
|
||||
TCCR0A = MASK(WGM01) | MASK(WGM00);
|
||||
TCCR0B = MASK(CS00);
|
||||
TIMSK0 = 0;
|
||||
OCR0A = 0;
|
||||
OCR0B = 255;
|
||||
OCR0B = 0;
|
||||
|
||||
TCCR2A = MASK(WGM21) | MASK(WGM20);
|
||||
TCCR2B = MASK(CS20);
|
||||
TIMSK2 = 0;
|
||||
OCR2A = 0;
|
||||
OCR2B = 0;
|
||||
|
||||
#ifdef TCCR3A
|
||||
TCCR3A = MASK(WGM31) | MASK(WGM30);
|
||||
TCCR3B = MASK(CS30);
|
||||
TIMSK3 = 0;
|
||||
OCR3A = 0;
|
||||
OCR3B = 0;
|
||||
#endif
|
||||
|
||||
#ifdef TCCR4A
|
||||
TCCR4A = MASK(WGM41) | MASK(WGM40);
|
||||
TCCR4B = MASK(CS40);
|
||||
TIMSK4 = 0;
|
||||
OCR4A = 0;
|
||||
OCR4B = 0;
|
||||
#endif
|
||||
|
||||
#ifdef TCCR5A
|
||||
TCCR5A = MASK(WGM51) | MASK(WGM50);
|
||||
TCCR5B = MASK(CS50);
|
||||
TIMSK5 = 0;
|
||||
OCR5A = 0;
|
||||
OCR5B = 0;
|
||||
#endif
|
||||
|
||||
#ifdef STEPPER_ENABLE_PIN
|
||||
|
|
@ -78,7 +117,6 @@ void io_init(void) {
|
|||
}
|
||||
|
||||
void init(void) {
|
||||
|
||||
// set up watchdog
|
||||
wd_init();
|
||||
|
||||
|
|
@ -89,10 +127,7 @@ void init(void) {
|
|||
io_init();
|
||||
|
||||
// set up timers
|
||||
setupTimerInterrupt();
|
||||
|
||||
// set up clock
|
||||
clock_setup();
|
||||
timer_init();
|
||||
|
||||
// read PID settings from EEPROM
|
||||
heater_init();
|
||||
|
|
@ -103,6 +138,9 @@ void init(void) {
|
|||
// start up analog read interrupt loop, if anything uses analog as determined by ANALOG_MASK in your config.h
|
||||
analog_init();
|
||||
|
||||
// set up temperature inputs
|
||||
temp_init();
|
||||
|
||||
// enable interrupts
|
||||
sei();
|
||||
|
||||
|
|
@ -114,48 +152,6 @@ void init(void) {
|
|||
|
||||
}
|
||||
|
||||
void clock_250ms(void) {
|
||||
// reset watchdog
|
||||
wd_reset();
|
||||
|
||||
temp_tick();
|
||||
|
||||
if (steptimeout > (30 * 4)) {
|
||||
power_off();
|
||||
}
|
||||
else
|
||||
steptimeout++;
|
||||
|
||||
ifclock(CLOCK_FLAG_1S) {
|
||||
if (debug_flags & DEBUG_POSITION) {
|
||||
// current position
|
||||
sersendf_P(PSTR("Pos: %ld,%ld,%ld,%ld,%lu\n"),
|
||||
(long int)current_position.X,
|
||||
(long int)current_position.Y,
|
||||
(long int)current_position.Z,
|
||||
(long int)current_position.E,
|
||||
(long unsigned int)current_position.F);
|
||||
|
||||
// target position
|
||||
sersendf_P(PSTR("Dst: %ld,%ld,%ld,%ld,%lu\n"),
|
||||
(long int)movebuffer[mb_tail].endpoint.X,
|
||||
(long int)movebuffer[mb_tail].endpoint.Y,
|
||||
(long int)movebuffer[mb_tail].endpoint.Z,
|
||||
(long int)movebuffer[mb_tail].endpoint.E,
|
||||
(long unsigned int)movebuffer[mb_tail].endpoint.F);
|
||||
|
||||
// Queue
|
||||
print_queue();
|
||||
}
|
||||
|
||||
#ifndef REPRAP_HOST_COMPATIBILITY
|
||||
// temperature
|
||||
if (temp_get_target())
|
||||
temp_print();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
init();
|
||||
|
|
@ -169,8 +165,8 @@ int main (void)
|
|||
gcode_parse_char(c);
|
||||
}
|
||||
|
||||
ifclock(CLOCK_FLAG_250MS) {
|
||||
clock_250ms();
|
||||
ifclock(CLOCK_FLAG_10MS) {
|
||||
clock_10ms();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
func.sh
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# this file is designed to be sourced into your current shell like this:
|
||||
#
|
||||
# source ./func.sh
|
||||
#
|
||||
# and then used like this:
|
||||
#
|
||||
# $ mendel_cmd G1 X100
|
||||
# $ mendel_cmd M250
|
||||
#
|
||||
# {X:4200,Y:0,Z:0,E:0,F:300,c:19334400}
|
||||
# {X:4200,Y:0,Z:0,E:0,F:300,c:0}
|
||||
# Q1/1E
|
||||
# $ mendel_readsym_uint8 mb_head
|
||||
# 1
|
||||
# $ mendel_readsym_target startpoint
|
||||
# X: 2100
|
||||
# Y: 0
|
||||
# Z: 0
|
||||
# E: 0
|
||||
# F: 300
|
||||
# $ mendel_readsym_mb
|
||||
# [0] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [HEAD,TAIL:1] {
|
||||
# eX: 4200 eY: 0 eZ: 0 eE: 0 eF: 300
|
||||
# flags: 120
|
||||
# dX: 4200 dY: 0 dZ: 0 dE: 0
|
||||
# cX: -2100 cY: -2100 cZ: -2100 cE: -2100
|
||||
# ts: 4200
|
||||
# c: 19334400 ec: 0 n: 0
|
||||
# }
|
||||
# [2] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [3] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [4] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [5] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [6] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
# [7] {
|
||||
# eX: 0 eY: 0 eZ: 0 eE: 0 eF: 0
|
||||
# flags: 0
|
||||
# dX: 0 dY: 0 dZ: 0 dE: 0
|
||||
# cX: 0 cY: 0 cZ: 0 cE: 0
|
||||
# ts: 0
|
||||
# c: 0 ec: 0 n: 0
|
||||
# }
|
||||
|
||||
|
||||
mendel_setup() {
|
||||
stty 115200 raw ignbrk -hup -echo ixoff < /dev/arduino
|
||||
}
|
||||
|
||||
mendel_reset() {
|
||||
stty hup < /dev/arduino
|
||||
stty hup < /dev/arduino
|
||||
mendel_setup
|
||||
}
|
||||
|
||||
mendel_talk() {
|
||||
( cat <&3 & cat >&3; kill $! ; ) 3<>/dev/arduino
|
||||
}
|
||||
|
||||
mendel_cmd() {
|
||||
(
|
||||
local IFS=$' \t\n'
|
||||
local RSC=0
|
||||
local cmd="$*"
|
||||
echo "$cmd" >&3;
|
||||
local REPLY=""
|
||||
while ! [[ "$REPLY" =~ ^OK ]] && ! [[ "$REPLY" =~ ^ok ]]
|
||||
do
|
||||
read -u 3
|
||||
echo "${REPLY##ok }"
|
||||
if [[ "$REPLY" =~ ^RESEND ]] || [[ "$REPLY" =~ ^rs ]]
|
||||
then
|
||||
if [ "$RSC" -le 3 ]
|
||||
then
|
||||
echo "$cmd" >&3
|
||||
RSC=$(( $RSC + 1 ))
|
||||
else
|
||||
REPLY="OK"
|
||||
echo "Too many retries: aborting" >&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
) 3<>/dev/arduino;
|
||||
}
|
||||
|
||||
mendel_cmd_hr() {
|
||||
(
|
||||
local IFS=$' \t\n'
|
||||
local cmd="$*"
|
||||
local RSC=0
|
||||
echo "$cmd" >&3
|
||||
echo "S> $cmd"
|
||||
local REPLY=""
|
||||
while ! [[ "$REPLY" =~ ^OK ]] && ! [[ "$REPLY" =~ ^ok ]]
|
||||
do
|
||||
read -u 3
|
||||
echo "<R $REPLY"
|
||||
if [[ "$REPLY" =~ ^RESEND ]] || [[ "$REPLY" =~ ^rs ]]
|
||||
then
|
||||
if [ "$RSC" -le 3 ]
|
||||
then
|
||||
echo "$cmd" >&3
|
||||
echo "S> $cmd"
|
||||
RSC=$(( $RSC + 1))
|
||||
else
|
||||
REPLY="OK"
|
||||
echo "Too many retries: aborting" >&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
) 3<>/dev/arduino;
|
||||
}
|
||||
|
||||
mendel_print() {
|
||||
(
|
||||
for F in "$@"
|
||||
do
|
||||
local IFS=$'\n'
|
||||
for L in $(< $F)
|
||||
do
|
||||
mendel_cmd_hr "$L"
|
||||
done
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
mendel_readsym() {
|
||||
(
|
||||
local IFS=$' \t\n'
|
||||
local sym=$1
|
||||
if [ -n "$sym" ]
|
||||
then
|
||||
if [[ "$sym" =~ ^(0?x?[0-9A-Fa-f]+)(:([0-9]+))?$ ]]
|
||||
then
|
||||
local ADDR=$(( ${BASH_REMATCH[1]} ))
|
||||
local SIZE=$(( ${BASH_REMATCH[3]} ))
|
||||
if [ "$SIZE" -le 1 ]
|
||||
then
|
||||
SIZE=1
|
||||
fi
|
||||
mendel_cmd "M253 S$ADDR P$SIZE"
|
||||
else
|
||||
make mendel.sym &>/dev/null
|
||||
if egrep -q '\b'$sym'\b' mendel.sym
|
||||
then
|
||||
local ADDR=$(( $(egrep '\b'$sym'\b' mendel.sym | cut -d\ -f1) ))
|
||||
local SIZE=$(egrep '\b'$sym'\b' mendel.sym | cut -d+ -f2)
|
||||
mendel_cmd "M253 S$ADDR P$SIZE"
|
||||
else
|
||||
echo "unknown symbol: $sym"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "what symbol?" > /dev/fd/2
|
||||
fi
|
||||
)
|
||||
}
|
||||
|
||||
mendel_readsym_uint8() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e 'printf "%u\n", eval "0x".$ARGV[0]' $val
|
||||
}
|
||||
|
||||
mendel_readsym_int8() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e 'printf "%d\n", ((eval "0x".$ARGV[0]) & 0x7F) - (((eval "0x".$ARGV[0]) & 0x80)?0x80:0)' $val
|
||||
}
|
||||
|
||||
mendel_readsym_uint16() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e '$ARGV[0] =~ m#(..)(..)# && printf "%u\n", eval "0x$2$1"' $val
|
||||
}
|
||||
|
||||
mendel_readsym_int16() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e '$ARGV[0] =~ m#(..)(..)# && printf "%d\n", ((eval "0x$2$1") & 0x7FFF) - (((eval "0x$2$1") & 0x8000)?0x8000:0)' $val
|
||||
}
|
||||
|
||||
mendel_readsym_uint32() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e '$ARGV[0] =~ m#(..)(..)(..)(..)# && printf "%u\n", eval "0x$4$3$2$1"' $val
|
||||
}
|
||||
|
||||
mendel_readsym_int32() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym $sym)
|
||||
perl -e '$ARGV[0] =~ m#(..)(..)(..)(..)# && printf "%d\n", eval "0x$4$3$2$1"' $val
|
||||
}
|
||||
|
||||
mendel_readsym_target() {
|
||||
local sym=$1
|
||||
local val=$(mendel_readsym "$sym")
|
||||
if [ -n "$val" ]
|
||||
then
|
||||
perl -e '@a = qw/X Y Z E F/; $c = 0; while (length $ARGV[0]) { $ARGV[0] =~ s#^(..)(..)(..)(..)##; printf "%s: %d\n", $a[$c], eval "0x$4$3$2$1"; $c++; }' "$val"
|
||||
fi
|
||||
}
|
||||
|
||||
mendel_readsym_mb() {
|
||||
local val=$(mendel_readsym movebuffer)
|
||||
local mbhead=$(mendel_readsym mb_head)
|
||||
local mbtail=$(mendel_readsym mb_tail)
|
||||
perl - <<'ENDPERL' -- $val $mbhead $mbtail
|
||||
$i = -1;
|
||||
@a = qw/eX 4 eY 4 eZ 4 eE 4 eF 4 flags 9 dX 12 dY 4 dZ 4 dE 4 cX 12 cY 4 cZ 4 cE 4 ts 12 c 12 rs 4 sn 4 cm 4 n 4 rs 1/;
|
||||
$c = 0;
|
||||
$c = 1234567;
|
||||
while (length $ARGV[1]) {
|
||||
if ($c > ($#a / 2)) {
|
||||
$i++;
|
||||
$c = 0;
|
||||
printf "\n}\n"
|
||||
if ($i > 0);
|
||||
printf "[%s%d] {\n", (($i == $ARGV[2])?"HEAD":"").(($ARGV[2] == $ARGV[3] && $ARGV[2] == $i)?",":"").(($i == $ARGV[3])?"TAIL":"").(($i == $ARGV[2] || $i == $ARGV[3])?":":""), $i
|
||||
}
|
||||
if ($a[$c * 2 + 1] & 8) {
|
||||
printf "\n";
|
||||
}
|
||||
if (($a[$c * 2 + 1] & 7) == 4) {
|
||||
$ARGV[1] =~ s#^(..)(..)(..)(..)##;
|
||||
printf "\t%s: %d", $a[$c * 2], eval "0x$4$3$2$1";
|
||||
}
|
||||
elsif (($a[$c * 2 + 1] & 7) == 1) {
|
||||
$ARGV[1] =~ s#^(..)##;
|
||||
printf "\t%s: %d", $a[$c * 2], eval "0x$1";
|
||||
}
|
||||
$c++;
|
||||
}
|
||||
printf "\n}\n";
|
||||
ENDPERL
|
||||
}
|
||||
|
||||
mendel_heater_pid() {
|
||||
local P=$(mendel_readsym_int16 heater_p)
|
||||
local I=$(mendel_readsym_int16 heater_i)
|
||||
local D=$(mendel_readsym_int16 heater_d)
|
||||
|
||||
local PF=$(mendel_readsym_int32 p_factor)
|
||||
local IF=$(mendel_readsym_int32 i_factor)
|
||||
local DF=$(mendel_readsym_int32 d_factor)
|
||||
|
||||
local O=$(mendel_readsym_uint8 0x27)
|
||||
local T=$(mendel_cmd M105 | cut -d\ -f2 | cut -d/ -f1)
|
||||
|
||||
echo "P=$P pf=$PF r="$(($P * $PF))
|
||||
echo "I=$I if=$IF r="$(($I * $IF))
|
||||
echo "D=$D df=$DF r="$(($D * $DF))
|
||||
echo "R="$(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024
|
||||
echo "R="$(( $(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024 ))
|
||||
echo "R="$(( $(( $(( $(($P * $PF)) + $(($I * $IF)) + $(($D * $DF)) )) / 1024 )) + 128 ))
|
||||
echo "O=$O T=$T"
|
||||
}
|
||||
|
||||
if [[ "$0" =~ ^mendel_(setup|reset|cmd|readsym|heater_pid) ]]
|
||||
then
|
||||
eval "$0" "$@"
|
||||
fi
|
||||
|
||||
if [[ "$1" =~ ^mendel_(setup|reset|cmd|readsym|heater_pid) ]]
|
||||
then
|
||||
eval "$@"
|
||||
fi
|
||||
4
serial.h
4
serial.h
|
|
@ -2,12 +2,8 @@
|
|||
#define _SERIAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
#include "simulation.h"
|
||||
|
||||
// initialise serial subsystem
|
||||
void serial_init(void);
|
||||
|
|
|
|||
116
serial_sim.c
116
serial_sim.c
|
|
@ -1,116 +0,0 @@
|
|||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "serial.h"
|
||||
#include "simulation.h"
|
||||
|
||||
static int serial_fd;
|
||||
static bool serial_initialised = false;
|
||||
|
||||
void serial_init(void)
|
||||
{
|
||||
struct termios options;
|
||||
|
||||
// hack to get argv and argc
|
||||
extern char ** environ;
|
||||
int argc = 1;
|
||||
char **argv = environ - 3;
|
||||
|
||||
while((int)*argv != argc)
|
||||
{
|
||||
++argc;
|
||||
--argv;
|
||||
}
|
||||
argv++;
|
||||
|
||||
sim_assert(argc >= 2, "please specify a serial port device name");
|
||||
|
||||
sim_info("opening serial port %s", argv[1]);
|
||||
serial_fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
sim_assert(serial_fd != -1, "couldn't open serial port");
|
||||
sim_assert(isatty(serial_fd), "not a TTY");
|
||||
|
||||
sim_info("configuring port");
|
||||
// Get the current options for the port
|
||||
if (tcgetattr(serial_fd, &options) != 0)
|
||||
{
|
||||
sim_error("tcgetattr");
|
||||
}
|
||||
|
||||
// Set the baud rates
|
||||
cfsetispeed(&options, B115200);
|
||||
cfsetospeed(&options, B115200);
|
||||
|
||||
// Enable the receiver and set local mode
|
||||
options.c_cflag |= (CLOCAL | CREAD);
|
||||
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
|
||||
// Set the new options for the port
|
||||
if (tcsetattr(serial_fd, TCSANOW, &options) != 0)
|
||||
{
|
||||
sim_error("tcsetattr");
|
||||
}
|
||||
|
||||
// flush tx and rx buffers
|
||||
tcflush(serial_fd, TCIOFLUSH);
|
||||
|
||||
serial_initialised = true;
|
||||
}
|
||||
|
||||
// return number of characters in the receive buffer
|
||||
uint8_t serial_rxchars(void)
|
||||
{
|
||||
int rx_chars_nb;
|
||||
sim_assert(serial_initialised, "serial interface not initialised");
|
||||
ioctl(serial_fd, FIONREAD, &rx_chars_nb);
|
||||
return rx_chars_nb;
|
||||
}
|
||||
|
||||
// read one character
|
||||
uint8_t serial_popchar(void)
|
||||
{
|
||||
uint8_t c;
|
||||
ssize_t count;
|
||||
|
||||
sim_assert(serial_initialised, "serial interface not initialised");
|
||||
sim_assert(serial_rxchars() > 0, "no chars to read");
|
||||
count = read(serial_fd, &c, 1);
|
||||
sim_assert(count == 1, "no character in serial RX buffer");
|
||||
return c;
|
||||
}
|
||||
|
||||
// send one character
|
||||
void serial_writechar(uint8_t data)
|
||||
{
|
||||
ssize_t count;
|
||||
sim_assert(serial_initialised, "serial interface not initialised");
|
||||
putchar(data);
|
||||
count = write(serial_fd, &data, 1);
|
||||
sim_assert(count == 1, "could not write to serial port");
|
||||
}
|
||||
|
||||
// read/write many characters
|
||||
void serial_writestr(uint8_t *data)
|
||||
{
|
||||
ssize_t count;
|
||||
const char *str = (char *)data;
|
||||
sim_assert(serial_initialised, "serial interface not initialised");
|
||||
puts(str);
|
||||
count = write(serial_fd, str, strlen(str));
|
||||
sim_assert(count == strlen(str), "could not write to serial port");
|
||||
}
|
||||
|
||||
// write from flash
|
||||
void serial_writestr_P(PGM_P data)
|
||||
{
|
||||
serial_writestr((uint8_t *)data);
|
||||
}
|
||||
|
||||
27
sersendf.c
27
sersendf.c
|
|
@ -1,9 +1,7 @@
|
|||
#include "sersendf.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#ifndef SIMULATION
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#include "serial.h"
|
||||
#include "sermsg.h"
|
||||
|
|
@ -21,18 +19,19 @@ void sersendf(char *format, ...) {
|
|||
switch(c) {
|
||||
case 'l':
|
||||
j = 4;
|
||||
break;
|
||||
case 'u':
|
||||
if (j == 4)
|
||||
serwrite_uint32(va_arg(args, uint32_t));
|
||||
else
|
||||
serwrite_uint16(va_arg(args, unsigned int));
|
||||
serwrite_uint16(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'd':
|
||||
if (j == 4)
|
||||
serwrite_int32(va_arg(args, int32_t));
|
||||
else
|
||||
serwrite_int16(va_arg(args, int));
|
||||
serwrite_int16(va_arg(args, int16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'p':
|
||||
|
|
@ -41,11 +40,11 @@ void sersendf(char *format, ...) {
|
|||
if (j == 4)
|
||||
serwrite_hex32(va_arg(args, uint32_t));
|
||||
else
|
||||
serwrite_hex16(va_arg(args, unsigned int));
|
||||
serwrite_hex16(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'c':
|
||||
serial_writechar(va_arg(args, unsigned int));
|
||||
serial_writechar(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 's':
|
||||
|
|
@ -53,6 +52,7 @@ void sersendf(char *format, ...) {
|
|||
j = 0;
|
||||
break;
|
||||
default:
|
||||
serial_writechar(c);
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -88,14 +88,18 @@ void sersendf_P(PGM_P format, ...) {
|
|||
if (j == 4)
|
||||
serwrite_uint32(va_arg(args, uint32_t));
|
||||
else
|
||||
serwrite_uint16(va_arg(args, unsigned int));
|
||||
serwrite_uint16(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'd':
|
||||
if (j == 4)
|
||||
serwrite_int32(va_arg(args, int32_t));
|
||||
else
|
||||
serwrite_int16(va_arg(args, int));
|
||||
serwrite_int16(va_arg(args, int16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'c':
|
||||
serial_writechar(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
/* case 'x':
|
||||
|
|
@ -108,13 +112,12 @@ void sersendf_P(PGM_P format, ...) {
|
|||
serwrite_hex16(va_arg(args, uint16_t));
|
||||
j = 0;
|
||||
break;
|
||||
case 'c':
|
||||
serial_writechar(va_arg(args, uint16_t));
|
||||
case 'p':
|
||||
serwrite_hex16(va_arg(args, uint16_t));
|
||||
serwrite_hex16(va_arg(args, uint16_t));*/
|
||||
default:
|
||||
serial_writechar(c);
|
||||
j = 0;
|
||||
break;*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
#ifndef _SERSENDF_H
|
||||
#define _SERSENDF_H
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
#include "simulation.h"
|
||||
|
||||
void sersendf(char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
void sersendf_P(PGM_P format, ...) __attribute__ ((format (printf, 1, 2)));
|
||||
|
|
|
|||
105
simulation.c
105
simulation.c
|
|
@ -1,105 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "simulation.h"
|
||||
|
||||
uint8_t ACSR;
|
||||
uint8_t TIMSK1;
|
||||
|
||||
|
||||
/* -- debugging ------------------------------------------------------------ */
|
||||
|
||||
void sim_info(const char fmt[], ...)
|
||||
{
|
||||
va_list ap;
|
||||
fputs("\033[0;32m" , stdout);
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
fputs("\033[m\n", stdout);
|
||||
}
|
||||
|
||||
void sim_error(const char msg[])
|
||||
{
|
||||
printf("\033[0;31mERROR: %s\033[m\n", msg);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void sim_assert(bool cond, const char msg[])
|
||||
{
|
||||
if (!cond)
|
||||
{
|
||||
sim_error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -- interrupts ----------------------------------------------------------- */
|
||||
|
||||
volatile bool sim_interrupts = false;
|
||||
void sei(void)
|
||||
{
|
||||
sim_interrupts = true;
|
||||
}
|
||||
|
||||
|
||||
/* -- PIN I/O ------------------------------------------------------------ */
|
||||
|
||||
#define out true
|
||||
#define in false
|
||||
|
||||
static int x = 0, y = 0, z = 0, e = 0;
|
||||
|
||||
static bool direction[PIN_NB];
|
||||
static bool state[PIN_NB];
|
||||
|
||||
static void print_pos(void)
|
||||
{
|
||||
sim_info("x:%5d y:%5d z:%5d e:%5d", x, y, z, e);
|
||||
}
|
||||
|
||||
void WRITE(pin_t pin, bool s)
|
||||
{
|
||||
bool old_state = state[pin];
|
||||
|
||||
if (direction[pin] == out)
|
||||
{
|
||||
state[pin] = s;
|
||||
}
|
||||
if (s && !old_state) /* rising edge */
|
||||
{
|
||||
switch (pin)
|
||||
{
|
||||
case X_STEP_PIN:
|
||||
x += state[X_DIR_PIN] ? 1 : -1;
|
||||
print_pos();
|
||||
break;
|
||||
case Y_STEP_PIN:
|
||||
y += state[Y_DIR_PIN] ? 1 : -1;
|
||||
print_pos();
|
||||
break;
|
||||
case Z_STEP_PIN:
|
||||
z += state[Z_DIR_PIN] ? 1 : -1;
|
||||
print_pos();
|
||||
break;
|
||||
case E_STEP_PIN:
|
||||
e += state[E_DIR_PIN] ? 1 : -1;
|
||||
print_pos();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SET_OUTPUT(pin_t pin)
|
||||
{
|
||||
direction[pin] = out;
|
||||
}
|
||||
|
||||
void SET_INPUT(pin_t pin)
|
||||
{
|
||||
direction[pin] = in;
|
||||
}
|
||||
|
||||
84
simulation.h
84
simulation.h
|
|
@ -1,84 +0,0 @@
|
|||
#if !defined _SIMULATION_H && defined SIMULATION
|
||||
#define _SIMULATION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PROGMEM
|
||||
#define PGM_P const char *
|
||||
#define PSTR(x) (x)
|
||||
#define pgm_read_byte(x) (*((uint8_t *)(x)))
|
||||
#define pgm_read_word(x) (*((uint16_t *)(x)))
|
||||
|
||||
#define MASK(PIN) (1 << PIN)
|
||||
#define ACD 7
|
||||
#define OCIE1A 1
|
||||
|
||||
|
||||
#undef X_STEP_PIN
|
||||
#undef X_DIR_PIN
|
||||
#undef X_MIN_PIN
|
||||
#undef Y_STEP_PIN
|
||||
#undef Y_DIR_PIN
|
||||
#undef Y_MIN_PIN
|
||||
#undef Z_STEP_PIN
|
||||
#undef Z_DIR_PIN
|
||||
#undef Z_MIN_PIN
|
||||
#undef E_STEP_PIN
|
||||
#undef E_DIR_PIN
|
||||
#undef STEPPER_ENABLE_PIN
|
||||
#undef HEATER_PIN
|
||||
#undef FAN_PIN
|
||||
#undef HEATER_PWM
|
||||
#undef FAN_PWM
|
||||
|
||||
typedef enum {
|
||||
X_STEP_PIN,
|
||||
X_DIR_PIN,
|
||||
X_MIN_PIN,
|
||||
Y_STEP_PIN,
|
||||
Y_DIR_PIN,
|
||||
Y_MIN_PIN,
|
||||
Z_STEP_PIN,
|
||||
Z_DIR_PIN,
|
||||
Z_MIN_PIN,
|
||||
E_STEP_PIN,
|
||||
E_DIR_PIN,
|
||||
|
||||
STEPPER_ENABLE_PIN,
|
||||
|
||||
SCK,
|
||||
MOSI,
|
||||
MISO,
|
||||
SS,
|
||||
|
||||
PIN_NB
|
||||
} pin_t;
|
||||
|
||||
#undef TEMP_PIN_CHANNEL
|
||||
#define TEMP_PIN_CHANNEL 0
|
||||
|
||||
extern uint8_t ACSR;
|
||||
extern uint8_t TIMSK1;
|
||||
extern volatile bool sim_interrupts;
|
||||
|
||||
void WRITE(pin_t pin, bool on);
|
||||
void SET_OUTPUT(pin_t pin);
|
||||
void SET_INPUT(pin_t pin);
|
||||
|
||||
void sei(void);
|
||||
|
||||
#ifdef USE_WATCHDOG
|
||||
#define wd_init()
|
||||
#define wd_reset()
|
||||
#endif
|
||||
|
||||
void sim_info(const char fmt[], ...);
|
||||
void sim_error(const char msg[]);
|
||||
void sim_assert(bool cond, const char msg[]);
|
||||
|
||||
#define ATOMIC_BLOCK(n) if (n)
|
||||
#define ATOMIC_RESTORESTATE 1
|
||||
|
||||
#endif /* _SIMULATION_H */
|
||||
|
||||
290
temp.c
290
temp.c
|
|
@ -1,35 +1,48 @@
|
|||
/*
|
||||
temp.c
|
||||
|
||||
This file currently reads temp from a MAX6675 on the SPI bus.
|
||||
|
||||
temp fields are 14.2 fixed point, so temp_set(500) will set the temperature to 125 celsius, and temp_get() = 600 is reporting a temperature of 150 celsius.
|
||||
|
||||
the conversion to/from this unit is done in gcode.c, near:
|
||||
if (next_target.M == 104)
|
||||
next_target.S = decfloat_to_int(&read_digit, 4, 1);
|
||||
and
|
||||
// M105- get temperature
|
||||
case 105:
|
||||
uint16_t t = temp_get();
|
||||
|
||||
note that the MAX6675 can't do more than approx 5 conversions per second- we go for 4 so the timing isn't too tight
|
||||
*/
|
||||
|
||||
#include "temp.h"
|
||||
|
||||
#ifndef SIMULATION
|
||||
#include <stdlib.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef enum {
|
||||
TT_THERMISTOR,
|
||||
TT_MAX6675,
|
||||
TT_AD595,
|
||||
TT_PT100,
|
||||
TT_INTERCOM,
|
||||
TT_DUMMY,
|
||||
} temp_types;
|
||||
|
||||
typedef enum {
|
||||
PRESENT,
|
||||
TCOPEN
|
||||
} temp_flags_enum;
|
||||
|
||||
#define TEMP_C
|
||||
#include "config.h"
|
||||
|
||||
#include "arduino.h"
|
||||
#include "delay.h"
|
||||
#include "debug.h"
|
||||
#ifndef EXTRUDER
|
||||
#include "sersendf.h"
|
||||
#endif
|
||||
#include "heater.h"
|
||||
#ifdef GEN3
|
||||
#include "intercom.h"
|
||||
#endif
|
||||
|
||||
#include "clock.h"
|
||||
#include "serial.h"
|
||||
#include "sermsg.h"
|
||||
#include "timer.h"
|
||||
#include "dda.h"
|
||||
#include "sersendf.h"
|
||||
#include "debug.h"
|
||||
#include "heater.h"
|
||||
// this struct holds the runtime sensor data- read temperatures, targets, etc
|
||||
struct {
|
||||
temp_flags_enum temp_flags;
|
||||
|
||||
uint16_t last_read_temp;
|
||||
uint16_t target_temp;
|
||||
|
||||
uint8_t temp_residency;
|
||||
|
||||
uint16_t next_read_time;
|
||||
} temp_sensors_runtime[NUM_TEMP_SENSORS];
|
||||
|
||||
#ifdef TEMP_MAX6675
|
||||
#endif
|
||||
|
|
@ -66,30 +79,50 @@ uint16_t temptable[NUMTEMPS][2] PROGMEM = {
|
|||
#include "analog.h"
|
||||
#endif
|
||||
|
||||
#ifndef TEMP_MAX6675
|
||||
#ifndef TEMP_THERMISTOR
|
||||
#ifndef TEMP_AD595
|
||||
#error none of TEMP_MAX6675, TEMP_THERMISTOR or TEMP_AD595 are defined! What type of temp sensor are you using?
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "simulation.h"
|
||||
|
||||
uint16_t current_temp = 0;
|
||||
uint16_t target_temp = 0;
|
||||
|
||||
uint8_t temp_flags = 0;
|
||||
uint8_t temp_residency = 0;
|
||||
|
||||
#ifndef ABSDELTA
|
||||
#define ABSDELTA(a, b) (((a) >= (b))?((a) - (b)):((b) - (a)))
|
||||
#endif
|
||||
|
||||
uint16_t temp_read() {
|
||||
uint16_t temp;
|
||||
|
||||
void temp_init() {
|
||||
uint8_t i;
|
||||
for (i = 0; i < NUM_TEMP_SENSORS; i++) {
|
||||
switch(temp_sensors[i].temp_type) {
|
||||
#ifdef TEMP_MAX6675
|
||||
// initialised when read
|
||||
/* case TT_MAX6675:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_THERMISTOR
|
||||
// handled by analog_init()
|
||||
/* case TT_THERMISTOR:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_AD595
|
||||
// handled by analog_init()
|
||||
/* case TT_AD595:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef GEN3
|
||||
case TT_INTERCOM:
|
||||
intercom_init();
|
||||
update_send_cmd(0);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void temp_sensor_tick() {
|
||||
uint8_t i = 0;
|
||||
for (; i < NUM_TEMP_SENSORS; i++) {
|
||||
if (temp_sensors_runtime[i].next_read_time) {
|
||||
temp_sensors_runtime[i].next_read_time--;
|
||||
}
|
||||
else {
|
||||
uint16_t temp = 0;
|
||||
//time to deal with this temp sensor
|
||||
switch(temp_sensors[i].temp_type) {
|
||||
#ifdef TEMP_MAX6675
|
||||
case TT_MAX6675:
|
||||
#ifdef PRR
|
||||
PRR &= ~MASK(PRSPI);
|
||||
#elif defined PRR0
|
||||
|
|
@ -98,7 +131,7 @@ uint16_t temp_read() {
|
|||
|
||||
SPCR = MASK(MSTR) | MASK(SPE) | MASK(SPR0);
|
||||
|
||||
// enable MAX6675
|
||||
// enable TT_MAX6675
|
||||
WRITE(SS, 0);
|
||||
|
||||
// ensure 100ns delay - a bit extra is fine
|
||||
|
|
@ -115,110 +148,143 @@ uint16_t temp_read() {
|
|||
for (;(SPSR & MASK(SPIF)) == 0;);
|
||||
temp |= SPDR;
|
||||
|
||||
// disable MAX6675
|
||||
// disable TT_MAX6675
|
||||
WRITE(SS, 1);
|
||||
|
||||
temp_flags = 0;
|
||||
temp_sensors_runtime[i].temp_flags = 0;
|
||||
if ((temp & 0x8002) == 0) {
|
||||
// got "device id"
|
||||
temp_flags |= TEMP_FLAG_PRESENT;
|
||||
temp_sensors_runtime[i].temp_flags |= PRESENT;
|
||||
if (temp & 4) {
|
||||
// thermocouple open
|
||||
temp_flags |= TEMP_FLAG_TCOPEN;
|
||||
temp_sensors_runtime[i].temp_flags |= TCOPEN;
|
||||
}
|
||||
else {
|
||||
current_temp = temp >> 3;
|
||||
return current_temp;
|
||||
temp = temp >> 3;
|
||||
}
|
||||
}
|
||||
|
||||
// this number depends on how frequently temp_sensor_tick is called. the MAX6675 can give a reading every 0.22s, so set this to about 250ms
|
||||
temp_sensors_runtime[i].next_read_time = 25;
|
||||
|
||||
break;
|
||||
#endif /* TEMP_MAX6675 */
|
||||
|
||||
#ifdef TEMP_THERMISTOR
|
||||
uint8_t i;
|
||||
|
||||
case TT_THERMISTOR:
|
||||
do {
|
||||
uint8_t j;
|
||||
//Read current temperature
|
||||
temp = analog_read(TEMP_PIN_CHANNEL);
|
||||
temp = analog_read(temp_sensors[i].temp_pin);
|
||||
|
||||
//Calculate real temperature based on lookup table
|
||||
for (i = 1; i < NUMTEMPS; i++) {
|
||||
if (pgm_read_word(&(temptable[i][0])) > temp) {
|
||||
for (j = 1; j < NUMTEMPS; j++) {
|
||||
if (pgm_read_word(&(temptable[j][0])) > temp) {
|
||||
// multiply by 4 because internal temp is stored as 14.2 fixed point
|
||||
temp = pgm_read_word(&(temptable[i][1])) + (pgm_read_word(&(temptable[i][0])) - temp) * 4 * (pgm_read_word(&(temptable[i-1][1])) - pgm_read_word(&(temptable[i][1]))) / (pgm_read_word(&(temptable[i][0])) - pgm_read_word(&(temptable[i-1][0])));
|
||||
temp = pgm_read_word(&(temptable[j][1])) * 4 + (pgm_read_word(&(temptable[j][0])) - temp) * 4 * (pgm_read_word(&(temptable[j-1][1])) - pgm_read_word(&(temptable[j][1]))) / (pgm_read_word(&(temptable[j][0])) - pgm_read_word(&(temptable[j-1][0])));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Clamp for overflows
|
||||
if (i == NUMTEMPS)
|
||||
temp = temptable[NUMTEMPS-1][1];
|
||||
|
||||
return temp;
|
||||
if (j == NUMTEMPS)
|
||||
temp = temptable[NUMTEMPS-1][1] * 4;
|
||||
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
} while (0);
|
||||
break;
|
||||
#endif /* TEMP_THERMISTOR */
|
||||
|
||||
#ifdef TEMP_AD595
|
||||
temp = analog_read(TEMP_PIN_CHANNEL);
|
||||
case TT_AD595:
|
||||
temp = analog_read(temp_pin);
|
||||
|
||||
// convert
|
||||
// >>8 instead of >>10 because internal temp is stored as 14.2 fixed point
|
||||
temp = (temp * 500L) >> 8;
|
||||
|
||||
return temp;
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
|
||||
break;
|
||||
#endif /* TEMP_AD595 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifdef TEMP_PT100
|
||||
case TT_PT100:
|
||||
#warning TODO: PT100 code
|
||||
break
|
||||
#endif /* TEMP_PT100 */
|
||||
|
||||
void temp_set(uint16_t t) {
|
||||
if (t) {
|
||||
steptimeout = 0;
|
||||
power_on();
|
||||
}
|
||||
target_temp = t;
|
||||
}
|
||||
#ifdef TEMP_INTERCOM
|
||||
case TT_INTERCOM:
|
||||
temp = get_read_cmd() << 2;
|
||||
|
||||
uint16_t temp_get() {
|
||||
return current_temp;
|
||||
}
|
||||
start_send();
|
||||
|
||||
uint16_t temp_get_target() {
|
||||
return target_temp;
|
||||
}
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
|
||||
void temp_print() {
|
||||
if (temp_flags & TEMP_FLAG_TCOPEN) {
|
||||
serial_writestr_P(PSTR("T: no thermocouple!\n"));
|
||||
break;
|
||||
#endif /* TEMP_INTERCOM */
|
||||
|
||||
#ifdef TEMP_DUMMY
|
||||
case TT_DUMMY:
|
||||
temp = temp_sensors_runtime[i].last_read_temp;
|
||||
|
||||
if (temp_sensors_runtime[i].target_temp > temp)
|
||||
temp++;
|
||||
else if (temp_sensors_runtime[i].target_temp < temp)
|
||||
temp--;
|
||||
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
|
||||
break;
|
||||
#endif /* TEMP_DUMMY */
|
||||
}
|
||||
temp_sensors_runtime[i].last_read_temp = temp;
|
||||
|
||||
if (labs(temp - temp_sensors_runtime[i].target_temp) < TEMP_HYSTERESIS) {
|
||||
if (temp_sensors_runtime[i].temp_residency < TEMP_RESIDENCY_TIME)
|
||||
temp_sensors_runtime[i].temp_residency++;
|
||||
}
|
||||
else {
|
||||
uint8_t c = 0, t = 0;
|
||||
|
||||
c = (current_temp & 3) * 25;
|
||||
t = (target_temp & 3) * 25;
|
||||
#ifdef REPRAP_HOST_COMPATIBILITY
|
||||
sersendf_P(PSTR(" T: %u.%u\n"), current_temp >> 2, c);
|
||||
#else
|
||||
sersendf_P(PSTR("T: %u.%u/%u.%u :%u\n"), current_temp >> 2, c, target_temp >> 2, t, temp_residency);
|
||||
#endif
|
||||
}
|
||||
temp_sensors_runtime[i].temp_residency = 0;
|
||||
}
|
||||
|
||||
void temp_tick() {
|
||||
if (target_temp) {
|
||||
steptimeout = 0;
|
||||
|
||||
temp_read();
|
||||
|
||||
heater_tick(current_temp, target_temp);
|
||||
|
||||
if (ABSDELTA(current_temp, target_temp) > TEMP_HYSTERESIS)
|
||||
temp_residency = 0;
|
||||
else if (temp_residency < TEMP_RESIDENCY_TIME)
|
||||
temp_residency++;
|
||||
if (temp_sensors[i].heater_index < NUM_HEATERS) {
|
||||
heater_tick(temp_sensors[i].heater_index, i, temp_sensors_runtime[i].last_read_temp, temp_sensors_runtime[i].target_temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t temp_achieved() {
|
||||
if (temp_residency >= TEMP_RESIDENCY_TIME)
|
||||
return 255;
|
||||
return 0;
|
||||
uint8_t i, all_ok = 255;
|
||||
for (i = 0; i < NUM_TEMP_SENSORS; i++) {
|
||||
if (temp_sensors_runtime[i].temp_residency < TEMP_RESIDENCY_TIME)
|
||||
all_ok = 0;
|
||||
}
|
||||
return all_ok;
|
||||
}
|
||||
|
||||
void temp_set(uint8_t index, uint16_t temperature) {
|
||||
temp_sensors_runtime[index].target_temp = temperature;
|
||||
temp_sensors_runtime[index].temp_residency = 0;
|
||||
#ifdef GEN3
|
||||
if (temp_sensors[index].temp_type == TT_INTERCOM)
|
||||
update_send_cmd(temperature >> 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t temp_get(uint8_t index) {
|
||||
return temp_sensors_runtime[index].last_read_temp;
|
||||
}
|
||||
|
||||
// extruder doesn't have sersendf_P
|
||||
#ifndef EXTRUDER
|
||||
void temp_print(uint8_t index) {
|
||||
uint8_t c = 0;
|
||||
|
||||
c = (temp_sensors_runtime[index].last_read_temp & 3) * 25;
|
||||
|
||||
sersendf_P(PSTR("T:%u.%u\n"), temp_sensors_runtime[index].last_read_temp >> 2, c);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
56
temp.h
56
temp.h
|
|
@ -3,59 +3,27 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
/*
|
||||
NOTES
|
||||
|
||||
#define TEMP_FLAG_PRESENT 1
|
||||
#define TEMP_FLAG_TCOPEN 2
|
||||
no point in specifying a port- all the different temp sensors we have must be on a particular port. The MAX6675 must be on the SPI, and the thermistor and AD595 must be on an analog port.
|
||||
|
||||
#ifdef TEMP_MAX6675
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t high;
|
||||
uint8_t low;
|
||||
} buf;
|
||||
struct {
|
||||
uint16_t dummy :1;
|
||||
uint16_t reading :12;
|
||||
uint16_t tc_open :1;
|
||||
uint16_t device_id :1;
|
||||
uint16_t tristate :1;
|
||||
} interpret;
|
||||
} max6675_data_format;
|
||||
#endif
|
||||
we still need to specify which analog pins we use in machine.h for the analog sensors however, otherwise the analog subsystem won't read them.
|
||||
*/
|
||||
|
||||
#if defined TEMP_THERMISTOR && !defined SIMULATION
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
#define temp_tick temp_sensor_tick
|
||||
|
||||
#ifdef TEMP_AD595
|
||||
#endif
|
||||
|
||||
// setup temperature system
|
||||
void temp_init(void);
|
||||
|
||||
// save PID factors to EEPROM
|
||||
void temp_save_settings(void);
|
||||
void temp_sensor_tick(void);
|
||||
|
||||
// read temperature from sensor
|
||||
uint16_t temp_read(void);
|
||||
|
||||
// set target temperature
|
||||
void temp_set(uint16_t t);
|
||||
|
||||
// return last read temperature
|
||||
uint16_t temp_get(void);
|
||||
|
||||
// return target temperature
|
||||
uint16_t temp_get_target(void);
|
||||
|
||||
// true if last read temp is close to target temp, false otherwise
|
||||
uint8_t temp_achieved(void);
|
||||
|
||||
// send current temperature to host
|
||||
void temp_print(void);
|
||||
void temp_set(uint8_t index, uint16_t temperature);
|
||||
uint16_t temp_get(uint8_t index);
|
||||
|
||||
// periodically read temperature and update heater with PID
|
||||
void temp_tick(void);
|
||||
void temp_print(uint8_t index);
|
||||
|
||||
uint16_t temp_read(uint8_t index);
|
||||
|
||||
#endif /* _TIMER_H */
|
||||
|
|
|
|||
178
timer.c
178
timer.c
|
|
@ -3,102 +3,118 @@
|
|||
#include <avr/interrupt.h>
|
||||
|
||||
#include "dda_queue.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
volatile uint32_t next_step_time;
|
||||
|
||||
uint8_t clock_counter_10ms = 0;
|
||||
uint8_t clock_counter_250ms = 0;
|
||||
uint8_t clock_counter_1s = 0;
|
||||
volatile uint8_t clock_flag = 0;
|
||||
|
||||
// timer overflow, happens every TICK_TIME
|
||||
ISR(TIMER1_CAPT_vect) {
|
||||
/*
|
||||
check if next step time will occur before next overflow
|
||||
*/
|
||||
if (next_step_time > TICK_TIME)
|
||||
next_step_time -= TICK_TIME;
|
||||
else if (next_step_time > 0) {
|
||||
OCR1A = next_step_time & 0xFFFF;
|
||||
TIMSK1 |= MASK(OCIE1A);
|
||||
}
|
||||
|
||||
/*
|
||||
clock stuff
|
||||
*/
|
||||
clock_counter_10ms += TICK_TIME_MS;
|
||||
if (clock_counter_10ms >= 10) {
|
||||
clock_counter_10ms -= 10;
|
||||
clock_flag |= CLOCK_FLAG_10MS;
|
||||
|
||||
clock_counter_250ms += 10;
|
||||
if (clock_counter_250ms >= 250) {
|
||||
clock_counter_250ms -= 250;
|
||||
clock_flag |= CLOCK_FLAG_250MS;
|
||||
|
||||
clock_counter_1s += 1;
|
||||
if (clock_counter_1s >= 4) {
|
||||
clock_counter_1s -= 4;
|
||||
clock_flag |= CLOCK_FLAG_1S;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void timer1_compa_isr(void) __attribute__ ((hot));
|
||||
void timer1_compa_isr() {
|
||||
// led on
|
||||
WRITE(SCK, 1);
|
||||
|
||||
// disable this interrupt. if we set a new timeout, it will be re-enabled when appropriate
|
||||
TIMSK1 &= ~MASK(OCIE1A);
|
||||
|
||||
// ensure we don't interrupt again unless timer is reset
|
||||
next_step_time = 0;
|
||||
|
||||
// stepper tick
|
||||
queue_step();
|
||||
|
||||
// led off
|
||||
WRITE(SCK, 0);
|
||||
}
|
||||
|
||||
void setupTimerInterrupt()
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
timer1_compa_isr();
|
||||
}
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
// no outputs
|
||||
TCCR1A = 0;
|
||||
// CTC mode
|
||||
TCCR1B = MASK(WGM12);
|
||||
// no interrupts yet
|
||||
TIMSK1 = 0;
|
||||
// CTC mode- use ICR for top
|
||||
TCCR1B = MASK(WGM13) | MASK(WGM12) | MASK(CS10);
|
||||
// set timeout- first timeout is indeterminate, probably doesn't matter
|
||||
ICR1 = TICK_TIME;
|
||||
// overflow interrupt (uses input capture interrupt in CTC:ICR mode)
|
||||
TIMSK1 = MASK(ICIE1);
|
||||
}
|
||||
|
||||
// the following are all from reprap project 5D firmware with some modification to reduce redundancy
|
||||
|
||||
uint8_t getTimerResolution(const uint32_t delay)
|
||||
{
|
||||
// these also represent frequency: 1000000 / delay / 2 = frequency in hz.
|
||||
|
||||
// our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs (4 millisecond max))
|
||||
// range: 8Mhz max - 122hz min
|
||||
if (delay <= 65535L)
|
||||
return 1;
|
||||
// our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs (32 millisecond max))
|
||||
// range:1Mhz max - 15.26hz min
|
||||
else if (delay <= 524280L)
|
||||
return 2;
|
||||
// our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs (0.26 seconds max))
|
||||
// range: 125Khz max - 1.9hz min
|
||||
else if (delay <= 4194240L)
|
||||
return 3;
|
||||
// our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs (1.04 seconds max))
|
||||
// range: 31.25Khz max - 0.475hz min
|
||||
else if (delay <= 16776960L)
|
||||
return 4;
|
||||
// our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs (4.19 seconds max))
|
||||
// range: 7.812Khz max - 0.119hz min
|
||||
//its really slow... hopefully we can just get by with super slow.
|
||||
return 5;
|
||||
}
|
||||
|
||||
void setTimerResolution(uint8_t r)
|
||||
{
|
||||
// assuming CS10,CS11,CS12 are adjacent bits in platform endian order,
|
||||
TCCR1B = (TCCR1B & ~(MASK(CS12) | MASK(CS11) | MASK(CS10))) | (r << CS10);
|
||||
}
|
||||
|
||||
uint16_t getTimerCeiling(const uint32_t delay)
|
||||
{
|
||||
// our slowest speed at our highest resolution ( (2^16-1) * 0.0625 usecs = 4095 usecs)
|
||||
if (delay <= 65535L)
|
||||
return (delay & 0xffff);
|
||||
// our slowest speed at our next highest resolution ( (2^16-1) * 0.5 usecs = 32767 usecs)
|
||||
else if (delay <= 524280L)
|
||||
return ((delay >> 3) & 0xffff);
|
||||
// our slowest speed at our medium resolution ( (2^16-1) * 4 usecs = 262140 usecs)
|
||||
else if (delay <= 4194240L)
|
||||
return ((delay >> 6) & 0xffff);
|
||||
// our slowest speed at our medium-low resolution ( (2^16-1) * 16 usecs = 1048560 usecs)
|
||||
else if (delay <= 16776960L)
|
||||
return ((delay >> 8) & 0xffff);
|
||||
// our slowest speed at our lowest resolution ((2^16-1) * 64 usecs = 4194240 usecs)
|
||||
else if (delay <= 67107840L)
|
||||
return ((delay >> 10) & 0xffff);
|
||||
//its really slow... hopefully we can just get by with super slow.
|
||||
else
|
||||
return 65535;
|
||||
}
|
||||
|
||||
|
||||
// Depending on how much work the interrupt function has to do, this is
|
||||
// pretty accurate between 10 us and 0.1 s. At fast speeds, the time
|
||||
// taken in the interrupt function becomes significant, of course.
|
||||
|
||||
// Note - it is up to the user to call enableTimerInterrupt() after a call
|
||||
// to this function.
|
||||
|
||||
void setTimer(uint32_t delay)
|
||||
{
|
||||
// delay is the delay between steps in IOclk ticks.
|
||||
//
|
||||
// we break it into 5 different resolutions based on the delay.
|
||||
// then we set the resolution based on the size of the delay.
|
||||
// we also then calculate the timer ceiling required. (ie what the counter counts to)
|
||||
// the result is the timer counts up to the appropriate time and then fires an interrupt.
|
||||
// save interrupt flag
|
||||
uint8_t sreg = SREG;
|
||||
// disable interrupts
|
||||
cli();
|
||||
|
||||
setTimerResolution(0); // stop timer
|
||||
GTCCR = MASK(PSRSYNC); // reset prescaler - affects timer 0 too but since it's doing PWM, it's not using the prescaler
|
||||
// re-enable clock interrupt in case we're recovering from emergency stop
|
||||
TIMSK1 |= MASK(ICIE1);
|
||||
|
||||
setTimerCeiling(getTimerCeiling(delay)); // set timeout
|
||||
setTimerResolution(getTimerResolution(delay)); // restart timer with proper prescaler
|
||||
if (delay > 0) {
|
||||
// mangle timer variables
|
||||
next_step_time = delay + TCNT1;
|
||||
if (delay <= 16) {
|
||||
// unfortunately, force registers don't trigger an interrupt, so we do the following
|
||||
// don't step from timer interrupt
|
||||
next_step_time = 0;
|
||||
// "fire" ISR- maybe it sets a new timeout
|
||||
timer1_compa_isr();
|
||||
}
|
||||
else if (delay <= TICK_TIME) {
|
||||
OCR1A = next_step_time & 0xFFFF;
|
||||
TIMSK1 |= MASK(OCIE1A);
|
||||
}
|
||||
}
|
||||
else {
|
||||
next_step_time = 0;
|
||||
}
|
||||
|
||||
// restore interrupt flag
|
||||
SREG = sreg;
|
||||
}
|
||||
|
||||
void timer_stop() {
|
||||
// disable all interrupts
|
||||
TIMSK1 = 0;
|
||||
// reset timeout
|
||||
next_step_time = 0;
|
||||
}
|
||||
|
|
|
|||
27
timer.h
27
timer.h
|
|
@ -2,30 +2,29 @@
|
|||
#define _TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef SIMULATION
|
||||
#include <avr/io.h>
|
||||
#endif
|
||||
#include "simulation.h"
|
||||
|
||||
// time-related constants
|
||||
#define US * (F_CPU / 1000000)
|
||||
#define MS * (F_CPU / 1000)
|
||||
|
||||
// #define DEFAULT_TICK (100 US)
|
||||
#define WAITING_DELAY (10 MS)
|
||||
/*
|
||||
clock stuff
|
||||
*/
|
||||
extern volatile uint8_t clock_flag;
|
||||
|
||||
void setupTimerInterrupt(void) __attribute__ ((cold));
|
||||
#define CLOCK_FLAG_10MS 1
|
||||
#define CLOCK_FLAG_250MS 2
|
||||
#define CLOCK_FLAG_1S 4
|
||||
#define ifclock(F) for (;clock_flag & (F);clock_flag &= ~(F))
|
||||
|
||||
uint8_t getTimerResolution(const uint32_t delay);
|
||||
void setTimerResolution(uint8_t r);
|
||||
|
||||
uint16_t getTimerCeiling(const uint32_t delay);
|
||||
#define setTimerCeiling(c) OCR1A = c
|
||||
/*
|
||||
timer stuff
|
||||
*/
|
||||
void timer_init(void) __attribute__ ((cold));
|
||||
|
||||
void setTimer(uint32_t delay);
|
||||
|
||||
#define enableTimerInterrupt() do { TIMSK1 |= (1<<OCIE1A); } while (0)
|
||||
#define disableTimerInterrupt() do { TIMSK1 &= ~(1<<OCIE1A); } while (0)
|
||||
#define timerInterruptIsEnabled() (TIMSK1 & (1 << OCIE1A))
|
||||
void timer_stop(void);
|
||||
|
||||
#endif /* _TIMER_H */
|
||||
|
|
|
|||
50
timer_sim.c
50
timer_sim.c
|
|
@ -1,50 +0,0 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "dda_queue.h"
|
||||
#include "timer.h"
|
||||
#include "simulation.h"
|
||||
|
||||
static bool timer_initialised = false;
|
||||
|
||||
void setupTimerInterrupt(void)
|
||||
{
|
||||
disableTimerInterrupt();
|
||||
sim_info("setupTimerInterrupt");
|
||||
timer_initialised = true;
|
||||
}
|
||||
|
||||
static void timer1_isr(int cause, siginfo_t *HowCome, void *ucontext)
|
||||
{
|
||||
if (!sim_interrupts || !timerInterruptIsEnabled()) return;
|
||||
|
||||
sim_interrupts = false;
|
||||
|
||||
WRITE(SCK, 1);
|
||||
queue_step();
|
||||
WRITE(SCK, 0);
|
||||
|
||||
sim_interrupts = true;
|
||||
}
|
||||
|
||||
void setTimer(uint32_t delay)
|
||||
{
|
||||
struct itimerval itimer;
|
||||
struct sigaction sa;
|
||||
|
||||
sim_assert(timer_initialised, "timer not initialised");
|
||||
|
||||
sa.sa_sigaction = timer1_isr;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGPROF, &sa, 0)) {
|
||||
sim_error("sigaction");
|
||||
}
|
||||
itimer.it_interval.tv_sec = 0;
|
||||
itimer.it_interval.tv_usec = (long)delay * 8000000 / F_CPU;
|
||||
itimer.it_value.tv_sec = 0;
|
||||
itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
|
||||
setitimer(ITIMER_PROF, &itimer, NULL);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue