merge release-candidate-triffid
This commit is contained in:
parent
56ce863024
commit
266c6ee0e2
|
|
@ -0,0 +1,144 @@
|
|||
##############################################################################
|
||||
# #
|
||||
# FiveD on Arduino - alternative firmware for repraps #
|
||||
# #
|
||||
# by Triffid Hunter, Traumflug, jakepoz #
|
||||
# #
|
||||
# #
|
||||
# This firmware is Copyright (C) 2009-2010 Michael Moon aka Triffid_Hunter #
|
||||
# #
|
||||
# This program is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program; if not, write to the Free Software #
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your application #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
PROGRAM = extruder
|
||||
|
||||
SOURCES = $(PROGRAM).c intercom.c delay.c analog.c watchdog.c heater.c temp.c
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Change these to suit your hardware #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
MCU_TARGET = atmega168
|
||||
F_CPU = 16000000L
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# These defaults should be ok, change if you need to #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
ARCH = avr-
|
||||
CC = $(ARCH)gcc
|
||||
OBJDUMP = $(ARCH)objdump
|
||||
OBJCOPY = $(ARCH)objcopy
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# Available Defines: #
|
||||
# #
|
||||
# DEBUG #
|
||||
# enables tons of debugging output. may cause host-side talkers to choke #
|
||||
# XONXOFF #
|
||||
# enables XON/XOFF flow control for stupid or crude talkers #
|
||||
# ACCELERATION_REPRAP #
|
||||
# enables reprap-style acceleration #
|
||||
# ACCELERATION_RAMPING #
|
||||
# enables start/stop ramping #
|
||||
# GEN3 #
|
||||
# build for standard reprap electronics instead of your custom rig #
|
||||
# #
|
||||
##############################################################################
|
||||
|
||||
DEFS = -DF_CPU=$(F_CPU) -DEXTRUDER -DGEN3
|
||||
# DEFS += "-DDEBUG=1"
|
||||
|
||||
OPTIMIZE = -Os -ffunction-sections -finline-functions-called-once
|
||||
# OPTIMIZE = -O0
|
||||
CFLAGS = -g -Wall -Wstrict-prototypes $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -save-temps
|
||||
LDFLAGS = -Wl,--as-needed -Wl,--gc-sections
|
||||
|
||||
AVRDUDE = avrdude
|
||||
AVRDUDECONF = /etc/avrdude.conf
|
||||
|
||||
##############################################################################
|
||||
# #
|
||||
# udev rule for /dev/arduino (insert into /etc/udev/rules.d/99-local.rules) #
|
||||
# SUBSYSTEMS=="usb", ATTRS{idProduct}=="6001", ATTRS{idVendor}=="0403", #
|
||||
# NAME="%k", SYMLINK+="arduino", SYMLINK+="arduino_$attr{serial}", #
|
||||
# MODE="0660" #
|
||||
# #
|
||||
##############################################################################
|
||||
PROGPORT = /dev/arduino
|
||||
PROGBAUD = 57600
|
||||
|
||||
OBJ = $(patsubst %.c,%.o,${SOURCES})
|
||||
|
||||
.PHONY: all program clean size
|
||||
.PRECIOUS: %.o %.elf
|
||||
|
||||
all: config.h $(PROGRAM).hex $(PROGRAM).lst $(PROGRAM).sym size
|
||||
|
||||
program: $(PROGRAM).hex config.h
|
||||
stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
@sleep 0.1
|
||||
@stty $(PROGBAUD) raw ignbrk hup < $(PROGPORT)
|
||||
$(AVRDUDE) -cstk500v1 -b$(PROGBAUD) -p$(MCU_TARGET) -P$(PROGPORT) -C$(AVRDUDECONF) -U flash:w:$^
|
||||
stty 115200 raw ignbrk -hup -echo ixoff < $(PROGPORT)
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.al *.i *.s *~
|
||||
|
||||
size: $(PROGRAM).elf
|
||||
@echo " SIZE Atmega168 Atmega328p Atmega644"
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(text)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " FLASH : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (14 * 1024)), 14, ceil($$a * 100 / (30 * 1024)), 30, ceil($$a * 100 / (63 * 1024)), 63 }'
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(data|bss)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " RAM : %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (4 * 1024)), 4 }'
|
||||
@$(OBJDUMP) -h $^ | perl -MPOSIX -ne '/.(eeprom)\s+([0-9a-f]+)/ && do { $$a += eval "0x$$2" }; END { printf " EEPROM: %5d bytes (%2d%% of %2dkb) (%2d%% of %2dkb) (%2d%% of %2dkb)\n", $$a, ceil($$a * 100 / (1 * 1024)), 1, ceil($$a * 100 / (2 * 1024)), 2, ceil($$a * 100 / (2 * 1024)), 2 }'
|
||||
|
||||
config.h: config.h.dist
|
||||
@echo "Please review config.h, as config.h.dist is more recent."
|
||||
@false
|
||||
|
||||
%.o: %.c config.h
|
||||
@echo " CC $@"
|
||||
@$(CC) -c $(CFLAGS) -Wa,-adhlns=$(<:.c=.al) -o $@ $(subst .o,.c,$@)
|
||||
|
||||
%.elf: $(OBJ)
|
||||
@echo " LINK $@"
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
%.lst: %.elf
|
||||
@echo " OBJDUMP $@"
|
||||
@$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
%.hex: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
@$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
%.bin: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
@$(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||
|
||||
%.sym: %.elf
|
||||
@echo " SYM $@"
|
||||
@$(OBJDUMP) -t $< | perl -ne 'BEGIN { printf " ADDR NAME SIZE\n"; } /([0-9a-f]+)\s+(\w+)\s+O\s+\.(bss|data)\s+([0-9a-f]+)\s+(\w+)/ && printf "0x%04x %-20s +%d\n", eval("0x$$1") & 0xFFFF, $$5, eval("0x$$4")' | sort -k1 > $@
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Reprap Gen3 extruder controller support for Triffid_Hunter's FiveD_on_Arduino firmware
|
||||
by jakepoz
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#include "analog.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#ifndef ANALOG_MASK
|
||||
#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() {
|
||||
#if ANALOG_MASK > 0
|
||||
#ifdef PRR
|
||||
PRR &= ~MASK(PRADC);
|
||||
#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;
|
||||
|
||||
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 /* ANALOG_MASK > 0 */
|
||||
}
|
||||
|
||||
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
|
||||
do {
|
||||
adc_counter++;
|
||||
adc_running_mask <<= 1;
|
||||
if (adc_counter == 8) {
|
||||
adc_counter = ANALOG_START;
|
||||
adc_running_mask = ANALOG_START_MASK;
|
||||
}
|
||||
} while ((adc_running_mask & ANALOG_MASK) == 0);
|
||||
|
||||
// start next conversion
|
||||
ADMUX = (adc_counter) | REFERENCE;
|
||||
ADCSRA |= MASK(ADSC);
|
||||
}
|
||||
|
||||
uint16_t analog_read(uint8_t channel) {
|
||||
#if ANALOG_MASK > 0
|
||||
uint16_t r;
|
||||
|
||||
uint8_t sreg;
|
||||
// save interrupt flag
|
||||
sreg = SREG;
|
||||
// disable interrupts
|
||||
cli();
|
||||
|
||||
// atomic 16-bit copy
|
||||
r = adc_result[channel];
|
||||
|
||||
// restore interrupt flag
|
||||
SREG = sreg;
|
||||
|
||||
return r;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef _ANALOG_H
|
||||
#define _ANALOG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define REFERENCE_AREF 0
|
||||
#define REFERENCE_AVCC 64
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
|
||||
#define REFERENCE_1V1 192
|
||||
#elif defined (__AVR_ATmega_644__) || defined (__AVR_ATmega644p__)
|
||||
#define REFERENCE_1V1 128
|
||||
#define REFERENCE_2V56 192
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef REFERENCE
|
||||
#warning define REFERENCE as one of
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
|
||||
#warning REFERENCE_AREF, REFERENCE_AVCC or REFERENCE_1V1
|
||||
#elif defined (__AVR_ATmega_644__) || defined (__AVR_ATmega644p__)
|
||||
#warning REFERENCE_AREF, REFERENCE_AVCC, REFERENCE_1V1 or REFERENCE_2V56
|
||||
#endif
|
||||
#warning in your config.h
|
||||
#error REFERENCE undefined
|
||||
#endif
|
||||
|
||||
void analog_init(void);
|
||||
uint16_t analog_read(uint8_t channel);
|
||||
|
||||
#endif /* _ANALOG_H */
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef _ARDUINO_H
|
||||
#define _ARDUINO_H
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
/*
|
||||
utility functions
|
||||
*/
|
||||
|
||||
#ifndef MASK
|
||||
#define MASK(PIN) (1 << PIN)
|
||||
#endif
|
||||
|
||||
/*
|
||||
magic I/O routines
|
||||
|
||||
now you can simply SET_OUTPUT(STEP); WRITE(STEP, 1); WRITE(STEP, 0);
|
||||
*/
|
||||
|
||||
#define _READ(IO) (IO ## _RPORT & MASK(IO ## _PIN))
|
||||
#define _WRITE(IO, v) do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)
|
||||
#define _TOGGLE(IO) do { IO ## _RPORT = MASK(IO ## _PIN); } while (0)
|
||||
|
||||
#define _SET_INPUT(IO) do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
|
||||
#define _SET_OUTPUT(IO) do { IO ## _DDR |= MASK(IO ## _PIN); } while (0)
|
||||
|
||||
#define _GET_INPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) == 0)
|
||||
#define _GET_OUTPUT(IO) ((IO ## _DDR & MASK(IO ## _PIN)) != 0)
|
||||
|
||||
// why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
|
||||
|
||||
#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)
|
||||
|
||||
/*
|
||||
ports and functions
|
||||
|
||||
added as necessary or if I feel like it- not a comprehensive list!
|
||||
*/
|
||||
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
|
||||
#include "arduino_168_328p.h"
|
||||
#endif /* _AVR_ATmega{168,328,328P}__ */
|
||||
|
||||
#if defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
|
||||
#include "arduino_644.h"
|
||||
#endif /* _AVR_ATmega{644,644P,644PA}__ */
|
||||
|
||||
#if defined (__AVR_ATmega1280__)
|
||||
#include "arduino_1280.h"
|
||||
#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
|
||||
#endif
|
||||
|
||||
#endif /* _ARDUINO_H */
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
// UART
|
||||
#define RXD DIO0
|
||||
#define TXD DIO1
|
||||
|
||||
// SPI
|
||||
#define SCK DIO13
|
||||
#define MISO DIO12
|
||||
#define MOSI DIO11
|
||||
#define SS DIO10
|
||||
|
||||
// TWI (I2C)
|
||||
#define SCL AIO5
|
||||
#define SDA AIO4
|
||||
|
||||
// timers and PWM
|
||||
#define OC0A DIO6
|
||||
#define OC0B DIO5
|
||||
#define OC1A DIO9
|
||||
#define OC1B DIO10
|
||||
#define OC2A DIO11
|
||||
#define OC2B DIO3
|
||||
|
||||
#define DEBUG_LED AIO5
|
||||
|
||||
/*
|
||||
pins
|
||||
*/
|
||||
|
||||
#define DIO0_PIN PIND0
|
||||
#define DIO0_RPORT PIND
|
||||
#define DIO0_WPORT PORTD
|
||||
#define DIO0_DDR DDRD
|
||||
|
||||
#define DIO1_PIN PIND1
|
||||
#define DIO1_RPORT PIND
|
||||
#define DIO1_WPORT PORTD
|
||||
#define DIO1_DDR DDRD
|
||||
|
||||
#define DIO2_PIN PIND2
|
||||
#define DIO2_RPORT PIND
|
||||
#define DIO2_WPORT PORTD
|
||||
#define DIO2_DDR DDRD
|
||||
|
||||
#define DIO3_PIN PIND3
|
||||
#define DIO3_RPORT PIND
|
||||
#define DIO3_WPORT PORTD
|
||||
#define DIO3_DDR DDRD
|
||||
|
||||
#define DIO4_PIN PIND4
|
||||
#define DIO4_RPORT PIND
|
||||
#define DIO4_WPORT PORTD
|
||||
#define DIO4_DDR DDRD
|
||||
|
||||
#define DIO5_PIN PIND5
|
||||
#define DIO5_RPORT PIND
|
||||
#define DIO5_WPORT PORTD
|
||||
#define DIO5_DDR DDRD
|
||||
|
||||
#define DIO6_PIN PIND6
|
||||
#define DIO6_RPORT PIND
|
||||
#define DIO6_WPORT PORTD
|
||||
#define DIO6_DDR DDRD
|
||||
|
||||
#define DIO7_PIN PIND7
|
||||
#define DIO7_RPORT PIND
|
||||
#define DIO7_WPORT PORTD
|
||||
#define DIO7_DDR DDRD
|
||||
|
||||
#define DIO8_PIN PINB0
|
||||
#define DIO8_RPORT PINB
|
||||
#define DIO8_WPORT PORTB
|
||||
#define DIO8_DDR DDRB
|
||||
|
||||
#define DIO9_PIN PINB1
|
||||
#define DIO9_RPORT PINB
|
||||
#define DIO9_WPORT PORTB
|
||||
#define DIO9_DDR DDRB
|
||||
|
||||
#define DIO10_PIN PINB2
|
||||
#define DIO10_RPORT PINB
|
||||
#define DIO10_WPORT PORTB
|
||||
#define DIO10_DDR DDRB
|
||||
|
||||
#define DIO11_PIN PINB3
|
||||
#define DIO11_RPORT PINB
|
||||
#define DIO11_WPORT PORTB
|
||||
#define DIO11_DDR DDRB
|
||||
|
||||
#define DIO12_PIN PINB4
|
||||
#define DIO12_RPORT PINB
|
||||
#define DIO12_WPORT PORTB
|
||||
#define DIO12_DDR DDRB
|
||||
|
||||
#define DIO13_PIN PINB5
|
||||
#define DIO13_RPORT PINB
|
||||
#define DIO13_WPORT PORTB
|
||||
#define DIO13_DDR DDRB
|
||||
|
||||
#define AIO0_PIN PINC0
|
||||
#define AIO0_RPORT PINC
|
||||
#define AIO0_WPORT PORTC
|
||||
#define AIO0_DDR DDRC
|
||||
|
||||
#define AIO1_PIN PINC1
|
||||
#define AIO1_RPORT PINC
|
||||
#define AIO1_WPORT PORTC
|
||||
#define AIO1_DDR DDRC
|
||||
|
||||
#define AIO2_PIN PINC2
|
||||
#define AIO2_RPORT PINC
|
||||
#define AIO2_WPORT PORTC
|
||||
#define AIO2_DDR DDRC
|
||||
|
||||
#define AIO3_PIN PINC3
|
||||
#define AIO3_RPORT PINC
|
||||
#define AIO3_WPORT PORTC
|
||||
#define AIO3_DDR DDRC
|
||||
|
||||
#define AIO4_PIN PINC4
|
||||
#define AIO4_RPORT PINC
|
||||
#define AIO4_WPORT PORTC
|
||||
#define AIO4_DDR DDRC
|
||||
|
||||
#define AIO5_PIN PINC5
|
||||
#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
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
#include "arduino.h"
|
||||
|
||||
//RS485 Interface pins
|
||||
#define RX_ENABLE_PIN DIO4
|
||||
#define TX_ENABLE_PIN AIO2
|
||||
|
||||
// Control pins for the A3949 chips
|
||||
#define H1D DIO7
|
||||
#define H1E DIO5
|
||||
#define H2D DIO8
|
||||
#define H2E DIO6
|
||||
|
||||
// PWM versions of the enable_pins
|
||||
#define H1E_PWM OCR0B
|
||||
#define H2E_PWM OCR0A
|
||||
|
||||
//Step/Dir Pins from motherboard to extruder
|
||||
//IMPORTANT: Assumes that the step pin is on PCIE0
|
||||
#define E_STEP_PIN DIO10
|
||||
#define E_DIR_PIN DIO9
|
||||
|
||||
//Trimpot is on AIO0, pin 23
|
||||
#define TRIM_POT AIO0
|
||||
#define TRIM_POT_CHANNEL 0
|
||||
|
||||
//Read analog voltage from thermistor
|
||||
#define TEMP_PIN AIO3
|
||||
#define TEMP_PIN_CHANNEL 3
|
||||
|
||||
#define REFERENCE REFERENCE_AVCC
|
||||
|
||||
#define ANALOG_MASK (MASK(TRIM_POT_CHANNEL) | MASK(TEMP_PIN_CHANNEL))
|
||||
|
||||
#define TEMP_THERMISTOR
|
||||
|
||||
// extruder settings
|
||||
#define TEMP_HYSTERESIS 20
|
||||
#define TEMP_RESIDENCY_TIME 60
|
||||
|
||||
#define NUM_TEMP_SENSORS 1
|
||||
#ifdef TEMP_C
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* Fill in the following struct according to your hardware *
|
||||
* *
|
||||
* If your temperature sensor has no associated heater, enter '255' as the *
|
||||
* heater index. *
|
||||
* *
|
||||
* for GEN3 set temp_type to TT_INTERCOM, temp_pin to 0 and heater index to *
|
||||
* 255 *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
|
||||
struct {
|
||||
uint8_t temp_type;
|
||||
uint8_t temp_pin;
|
||||
|
||||
uint8_t heater_index;
|
||||
} temp_sensors[NUM_TEMP_SENSORS] =
|
||||
{
|
||||
{
|
||||
TT_THERMISTOR,
|
||||
PINC3,
|
||||
0
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// list of PWM-able pins and corresponding timers
|
||||
// timer1 is used for step timing so don't use OC1A/OC1B (DIO9/DIO10)
|
||||
// OC0A DIO6
|
||||
// OC0B DIO5
|
||||
// OC1A DIO9
|
||||
// OC1B DIO10
|
||||
// OC2A DIO11
|
||||
// OC2B DIO3
|
||||
|
||||
#define TH_COUNT 8
|
||||
#define PID_SCALE 1024L
|
||||
|
||||
#define NUM_HEATERS 2
|
||||
#ifdef HEATER_C
|
||||
/***************************************************************************\
|
||||
* *
|
||||
* Fill in the following struct according to your hardware *
|
||||
* *
|
||||
* For the atmega168/328, timer/pin mappings are as follows *
|
||||
* *
|
||||
* OCR0A - PD6 *
|
||||
* OCR0B - PD5 *
|
||||
* OCR2A - PB3 *
|
||||
* OCR2B - PD3 *
|
||||
* *
|
||||
\***************************************************************************/
|
||||
struct {
|
||||
volatile uint8_t *heater_port;
|
||||
uint8_t heater_pin;
|
||||
volatile uint8_t *heater_pwm;
|
||||
} heaters[NUM_HEATERS] =
|
||||
{
|
||||
{
|
||||
&PORTD,
|
||||
PIND6,
|
||||
&OCR0A
|
||||
},
|
||||
{
|
||||
&PORTB,
|
||||
PINB4,
|
||||
0
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// #define HEATER_PIN DIO11
|
||||
// #define HEATER_PWM OCR2A
|
||||
//
|
||||
// #define BED_PIN DIO12
|
||||
|
||||
/*
|
||||
Intercom
|
||||
*/
|
||||
#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
|
||||
/*
|
||||
Motors
|
||||
*/
|
||||
|
||||
#define enable_motors() do { TCCR0A |= MASK(COM0A1) | MASK(COM0B1); } while (0)
|
||||
#define disable_motors() do { TCCR0A &= ~MASK(COM0A1) & ~MASK(COM0B1); } while (0)
|
||||
|
||||
/*
|
||||
Heater
|
||||
*/
|
||||
|
||||
// #ifdef HEATER_PWM
|
||||
// #define enable_heater() do { TCCR2A |= MASK(COM2A1); } while (0)
|
||||
// #define disable_heater() do { TCCR2A &= ~MASK(COM2A1); } while (0)
|
||||
// #else
|
||||
// #define enable_heater() WRITE(HEATER_PIN, 1)
|
||||
// #define disable_heater() WRITE(HEATER_PIN, 0)
|
||||
// #endif
|
||||
|
||||
#endif /* _CONFIG_H */
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef _DEBUG_H
|
||||
#define _DEBUG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_PID 1
|
||||
#define DEBUG_DDA 2
|
||||
#define DEBUG_POSITION 4
|
||||
#else
|
||||
// by setting these to zero, the compiler should optimise the relevant code out
|
||||
#define DEBUG_PID 0
|
||||
#define DEBUG_DDA 0
|
||||
#define DEBUG_POSITION 0
|
||||
#endif
|
||||
|
||||
#define DEBUG_ECHO 128
|
||||
|
||||
extern volatile uint8_t debug_flags;
|
||||
|
||||
#endif /* _DEBUG_H */
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#include "delay.h"
|
||||
|
||||
#include "watchdog.h"
|
||||
|
||||
// delay( microseconds )
|
||||
void delay(uint32_t delay) {
|
||||
wd_reset();
|
||||
while (delay > 65535) {
|
||||
delayMicrosecondsInterruptible(65533);
|
||||
delay -= 65535;
|
||||
wd_reset();
|
||||
}
|
||||
delayMicrosecondsInterruptible(delay & 0xFFFF);
|
||||
wd_reset();
|
||||
}
|
||||
|
||||
// delay_ms( milliseconds )
|
||||
void delay_ms(uint32_t delay) {
|
||||
wd_reset();
|
||||
while (delay > 65) {
|
||||
delayMicrosecondsInterruptible(64999);
|
||||
delay -= 65;
|
||||
wd_reset();
|
||||
}
|
||||
delayMicrosecondsInterruptible(delay * 1000);
|
||||
wd_reset();
|
||||
}
|
||||
|
||||
void delayMicrosecondsInterruptible(uint16_t us)
|
||||
{
|
||||
// for a one-microsecond delay, simply return. the overhead
|
||||
// of the function call yields a delay of approximately 1 1/8 us.
|
||||
if (--us == 0)
|
||||
return;
|
||||
|
||||
// the following loop takes a quarter of a microsecond (4 cycles)
|
||||
// per iteration, so execute it four times for each microsecond of
|
||||
// delay requested.
|
||||
us <<= 2;
|
||||
|
||||
// account for the time taken in the preceeding commands.
|
||||
us -= 2;
|
||||
|
||||
// busy wait
|
||||
__asm__ __volatile__ ("1: sbiw %0,1" "\n\t" // 2 cycles
|
||||
"brne 1b" :
|
||||
"=w" (us) :
|
||||
"0" (us) // 2 cycles
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _DELAY_H
|
||||
#define _DELAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define WAITING_DELAY 10 MS
|
||||
|
||||
void delay(uint32_t delay);
|
||||
|
||||
void delay_ms(uint32_t delay);
|
||||
|
||||
#define delay_us(d) delayMicrosecondsInterruptible(d)
|
||||
void delayMicrosecondsInterruptible(unsigned int us);
|
||||
|
||||
#endif /* _DELAY_H */
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "intercom.h"
|
||||
#include "analog.h"
|
||||
#include "config.h"
|
||||
#include "watchdog.h"
|
||||
#include "heater.h"
|
||||
#include "temp.h"
|
||||
|
||||
static uint8_t motor_pwm;
|
||||
|
||||
void io_init(void) {
|
||||
// setup I/O pins
|
||||
WRITE(DEBUG_LED, 0); SET_OUTPUT(DEBUG_LED);
|
||||
WRITE(H1D,0); SET_OUTPUT(H1D);
|
||||
WRITE(H1E,0); SET_OUTPUT(H1E);
|
||||
WRITE(H2D,0); SET_OUTPUT(H2D);
|
||||
WRITE(H2E,0); SET_OUTPUT(H2E);
|
||||
|
||||
SET_INPUT(TRIM_POT);
|
||||
SET_INPUT(TEMP_PIN);
|
||||
SET_INPUT(E_STEP_PIN);
|
||||
SET_INPUT(E_DIR_PIN);
|
||||
|
||||
//Enable the RS485 transceiver
|
||||
SET_OUTPUT(RX_ENABLE_PIN);
|
||||
SET_OUTPUT(TX_ENABLE_PIN);
|
||||
disable_transmit();
|
||||
|
||||
#ifdef HEATER_PIN
|
||||
WRITE(HEATER_PIN, 0); SET_OUTPUT(HEATER_PIN);
|
||||
#endif
|
||||
|
||||
#ifdef BED_PIN
|
||||
WRITE(BED_PIN, 0); SET_OUTPUT(BED_PIN);
|
||||
#endif
|
||||
|
||||
// #if defined(HEATER_PWM) || defined(FAN_PWM) || defined(BED_PWM)
|
||||
// setup PWM timer: fast PWM, no prescaler
|
||||
TCCR2A = MASK(WGM21) | MASK(WGM20);
|
||||
TCCR2B = MASK(CS22);
|
||||
TIMSK2 = 0;
|
||||
OCR2A = 0;
|
||||
OCR2B = 0;
|
||||
// #endif
|
||||
|
||||
#if defined(H1E_PWM) && defined(H2E_PWM)
|
||||
TCCR0A = MASK(WGM01) | MASK(WGM00);
|
||||
TCCR0B = MASK(CS20);
|
||||
TIMSK0 = 0;
|
||||
OCR0A = 0;
|
||||
OCR0B = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void motor_init(void) {
|
||||
//Enable an interrupt to be triggered when the step pin changes
|
||||
//This will be PCIE0
|
||||
PCICR = MASK(PCIE0);
|
||||
PCMSK0 = MASK(PCINT2);
|
||||
}
|
||||
|
||||
ISR(PCINT0_vect) {
|
||||
static uint8_t coil_pos, pwm, flag;
|
||||
|
||||
if (flag == 1) flag = 0;
|
||||
else flag = 1;
|
||||
|
||||
//if the step pin is high, we advance the motor
|
||||
if (flag) {
|
||||
|
||||
//Turn on motors only on first tick to save power I guess
|
||||
enable_motors();
|
||||
|
||||
//Advance the coil position
|
||||
if (READ(E_DIR_PIN))
|
||||
coil_pos++;
|
||||
else
|
||||
coil_pos--;
|
||||
|
||||
coil_pos &= 31;
|
||||
|
||||
//Grab the latest motor power to use
|
||||
pwm = motor_pwm;
|
||||
|
||||
switch(coil_pos >> 2) {
|
||||
case 0:
|
||||
WRITE(H1D, 0);
|
||||
WRITE(H2D, 0);
|
||||
H1E_PWM = 0;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
case 1:
|
||||
WRITE(H1D, 1);
|
||||
WRITE(H2D, 0);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
case 2:
|
||||
WRITE(H1D, 1);
|
||||
WRITE(H2D, 0);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = 0;
|
||||
break;
|
||||
case 3:
|
||||
WRITE(H1D, 1);
|
||||
WRITE(H2D, 1);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
case 4:
|
||||
WRITE(H1D, 1);
|
||||
WRITE(H2D, 1);
|
||||
H1E_PWM = 0;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
case 5:
|
||||
WRITE(H1D, 0);
|
||||
WRITE(H2D, 1);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
case 6:
|
||||
WRITE(H1D, 0);
|
||||
WRITE(H2D, 1);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = 0;
|
||||
break;
|
||||
case 7:
|
||||
WRITE(H1D, 0);
|
||||
WRITE(H2D, 0);
|
||||
H1E_PWM = pwm;
|
||||
H2E_PWM = pwm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init(void) {
|
||||
// set up watchdog
|
||||
wd_init();
|
||||
|
||||
// setup analog reading
|
||||
analog_init();
|
||||
|
||||
// set up serial
|
||||
intercom_init();
|
||||
|
||||
// set up inputs and outputs
|
||||
io_init();
|
||||
|
||||
// temp sensor
|
||||
temp_init();
|
||||
|
||||
// heater
|
||||
heater_init();
|
||||
|
||||
// set up extruder motor driver
|
||||
motor_init();
|
||||
|
||||
// enable interrupts
|
||||
sei();
|
||||
|
||||
// reset watchdog
|
||||
wd_reset();
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
init();
|
||||
|
||||
enable_heater();
|
||||
|
||||
start_send();
|
||||
|
||||
// main loop
|
||||
for (;;)
|
||||
{
|
||||
wd_reset();
|
||||
|
||||
//Read motor PWM
|
||||
motor_pwm = analog_read(TRIM_POT_CHANNEL) >> 2;
|
||||
|
||||
temp_sensor_tick();
|
||||
|
||||
update_send_cmd(temp_get(0) >> 2);
|
||||
temp_set(0, get_read_cmd());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
#include "heater.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#include "arduino.h"
|
||||
#include "debug.h"
|
||||
#ifndef EXTRUDER
|
||||
#include "sersendf.h"
|
||||
#endif
|
||||
|
||||
#define HEATER_C
|
||||
#include "config.h"
|
||||
|
||||
// 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_I_LIMIT 384
|
||||
|
||||
// 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;
|
||||
|
||||
EE_factor EEMEM EE_factors[NUM_HEATERS];
|
||||
|
||||
void heater_init() {
|
||||
#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
|
||||
}
|
||||
|
||||
void heater_save_settings() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp) {
|
||||
#if NUM_HEATERS > 0
|
||||
int16_t heater_p;
|
||||
int16_t heater_d;
|
||||
uint8_t pid_output;
|
||||
|
||||
int16_t t_error = target_temp - current_temp;
|
||||
|
||||
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
|
||||
heaters_runtime[h].heater_i += t_error;
|
||||
// prevent integrator wind-up
|
||||
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 = heaters_runtime[h].temp_history[heaters_runtime[h].temp_history_pointer] - current_temp;
|
||||
|
||||
// combine factors
|
||||
int32_t pid_output_intermed = (
|
||||
(
|
||||
(((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
|
||||
if (pid_output_intermed > 255)
|
||||
pid_output = 255;
|
||||
else if (pid_output_intermed < 0)
|
||||
pid_output = 0;
|
||||
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, 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;
|
||||
}
|
||||
|
||||
// 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 broken- temp is %d.%dC, target is %d.%dC, didn't reach %d.%dC in %d0 milliseconds\n"), h, 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 */
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef _HEATER_H
|
||||
#define _HEATER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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_set(uint8_t index, uint8_t value);
|
||||
void heater_tick(uint8_t h, uint16_t current_temp, uint16_t target_temp);
|
||||
|
||||
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_H */
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
#include "intercom.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "delay.h"
|
||||
|
||||
#ifdef GEN3
|
||||
#define INTERCOM_BAUD 57600
|
||||
|
||||
#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
|
||||
/*
|
||||
Defines a super simple intercom interface using the RS485 modules
|
||||
|
||||
Host will say: START1 START2 PWM_CMD PWM_CHK
|
||||
Extruder will reply: START1 START2 TMP_CMD TMP_CHK
|
||||
|
||||
CHK = 255-CMD, if they match do the work, if not, ignore this packet
|
||||
|
||||
in a loop
|
||||
*/
|
||||
|
||||
|
||||
#define START1 0xAA
|
||||
#define START2 0x55
|
||||
|
||||
typedef enum {
|
||||
SEND_START1,
|
||||
SEND_START2,
|
||||
SEND_CMD,
|
||||
SEND_CHK,
|
||||
SEND_DONE,
|
||||
|
||||
READ_START1,
|
||||
READ_START2,
|
||||
READ_CMD,
|
||||
READ_CHK,
|
||||
} intercom_state_e;
|
||||
|
||||
|
||||
intercom_state_e state = READ_START1;
|
||||
uint8_t cmd, chk, send_cmd, read_cmd;
|
||||
|
||||
void intercom_init(void)
|
||||
{
|
||||
#ifdef HOST
|
||||
#if INTERCOM_BAUD > 38401
|
||||
UCSR1A = MASK(U2X1);
|
||||
UBRR1 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5);
|
||||
#else
|
||||
UCSR1A = 0;
|
||||
UBRR1 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5);
|
||||
#endif
|
||||
UCSR1B = MASK(RXEN1) | MASK(TXEN1);
|
||||
UCSR1C = MASK(UCSZ11) | MASK(UCSZ10);
|
||||
|
||||
UCSR1B |= MASK(RXCIE1) | MASK(TXCIE1);
|
||||
#else
|
||||
#if INTERCOM_BAUD > 38401
|
||||
UCSR0A = MASK(U2X0);
|
||||
UBRR0 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5);
|
||||
#else
|
||||
UCSR0A = 0;
|
||||
UBRR0 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5);
|
||||
#endif
|
||||
UCSR0B = MASK(RXEN0) | MASK(TXEN0);
|
||||
UCSR0C = MASK(UCSZ01) | MASK(UCSZ00);
|
||||
|
||||
UCSR0B |= MASK(RXCIE0) | MASK(TXCIE0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_send_cmd(uint8_t new_send_cmd) {
|
||||
send_cmd = new_send_cmd;
|
||||
}
|
||||
|
||||
uint8_t get_read_cmd(void) {
|
||||
return read_cmd;
|
||||
}
|
||||
|
||||
static void write_byte(uint8_t val) {
|
||||
#ifdef HOST
|
||||
UDR1 = val;
|
||||
#else
|
||||
UDR0 = val;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void start_send(void) {
|
||||
state = SEND_START1;
|
||||
enable_transmit();
|
||||
delay_us(15);
|
||||
//Enable interrupts so we can send next characters
|
||||
#ifdef HOST
|
||||
UCSR1B |= MASK(UDRIE1);
|
||||
#else
|
||||
UCSR0B |= MASK(UDRIE0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void finish_send(void) {
|
||||
state = READ_START1;
|
||||
disable_transmit();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Interrupts, UART 0 for mendel
|
||||
*/
|
||||
#ifdef HOST
|
||||
ISR(USART1_RX_vect)
|
||||
#else
|
||||
ISR(USART_RX_vect)
|
||||
#endif
|
||||
{
|
||||
static uint8_t c;
|
||||
|
||||
#ifdef HOST
|
||||
c = UDR1;
|
||||
UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1);
|
||||
#else
|
||||
c = UDR0;
|
||||
UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0);
|
||||
#endif
|
||||
|
||||
if (state >= READ_START1) {
|
||||
|
||||
switch(state) {
|
||||
case READ_START1:
|
||||
if (c == START1) state = READ_START2;
|
||||
break;
|
||||
case READ_START2:
|
||||
if (c == START2) state = READ_CMD;
|
||||
else state = READ_START1;
|
||||
break;
|
||||
case READ_CMD:
|
||||
cmd = c;
|
||||
state = READ_CHK;
|
||||
break;
|
||||
case READ_CHK:
|
||||
chk = c;
|
||||
|
||||
if (chk == 255 - cmd) {
|
||||
//Values are correct, do something useful
|
||||
WRITE(DEBUG_LED,1);
|
||||
read_cmd = cmd;
|
||||
#ifdef EXTRUDER
|
||||
start_send();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
state = READ_START1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef HOST
|
||||
ISR(USART1_TX_vect)
|
||||
#else
|
||||
ISR(USART_TX_vect)
|
||||
#endif
|
||||
{
|
||||
if (state == SEND_DONE) {
|
||||
finish_send();
|
||||
|
||||
|
||||
#ifdef HOST
|
||||
UCSR1B &= ~MASK(TXCIE1);
|
||||
#else
|
||||
UCSR0B &= ~MASK(TXCIE0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HOST
|
||||
ISR(USART1_UDRE_vect)
|
||||
#else
|
||||
ISR(USART_UDRE_vect)
|
||||
#endif
|
||||
{
|
||||
switch(state) {
|
||||
case SEND_START1:
|
||||
write_byte(START1);
|
||||
state = SEND_START2;
|
||||
break;
|
||||
case SEND_START2:
|
||||
write_byte(START2);
|
||||
state = SEND_CMD;
|
||||
break;
|
||||
case SEND_CMD:
|
||||
write_byte(send_cmd);
|
||||
state = SEND_CHK;
|
||||
break;
|
||||
case SEND_CHK:
|
||||
write_byte(255 - send_cmd);
|
||||
state = SEND_DONE;
|
||||
#ifdef HOST
|
||||
UCSR1B &= ~MASK(UDRIE1);
|
||||
UCSR1B |= MASK(TXCIE1);
|
||||
#else
|
||||
UCSR0B &= ~MASK(UDRIE0);
|
||||
UCSR0B |= MASK(TXCIE0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GEN3 */
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _INTERCOM_H
|
||||
#define _INTERCOM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// initialise serial subsystem
|
||||
void intercom_init(void);
|
||||
|
||||
//Update the message we are sending over intercom
|
||||
void update_send_cmd(uint8_t new_send_cmd);
|
||||
|
||||
void start_send(void);
|
||||
|
||||
//Read the message we are receiving over intercom
|
||||
uint8_t get_read_cmd(void);
|
||||
|
||||
#endif /* _INTERCOM_H */
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
#include "temp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
typedef enum {
|
||||
TT_THERMISTOR,
|
||||
TT_MAX6675,
|
||||
TT_AD595,
|
||||
TT_PT100,
|
||||
TT_INTERCOM
|
||||
} 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
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef TEMP_THERMISTOR
|
||||
#include "analog.h"
|
||||
|
||||
#define NUMTEMPS 20
|
||||
uint16_t temptable[NUMTEMPS][2] PROGMEM = {
|
||||
{1, 841},
|
||||
{54, 255},
|
||||
{107, 209},
|
||||
{160, 184},
|
||||
{213, 166},
|
||||
{266, 153},
|
||||
{319, 142},
|
||||
{372, 132},
|
||||
{425, 124},
|
||||
{478, 116},
|
||||
{531, 108},
|
||||
{584, 101},
|
||||
{637, 93},
|
||||
{690, 86},
|
||||
{743, 78},
|
||||
{796, 70},
|
||||
{849, 61},
|
||||
{902, 50},
|
||||
{955, 34},
|
||||
{1008, 3}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_AD595
|
||||
#include "analog.h"
|
||||
#endif
|
||||
|
||||
void temp_init() {
|
||||
uint8_t i;
|
||||
for (i = 0; i < NUM_TEMP_SENSORS; i++) {
|
||||
switch(temp_sensors[i].temp_type) {
|
||||
#ifdef TEMP_MAX6675
|
||||
// initialised when read
|
||||
/* case TT_MAX6675:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_THERMISTOR
|
||||
// handled by analog_init()
|
||||
/* case TT_THERMISTOR:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef TEMP_AD595
|
||||
// handled by analog_init()
|
||||
/* case TT_AD595:
|
||||
break;*/
|
||||
#endif
|
||||
|
||||
#ifdef GEN3
|
||||
case TT_INTERCOM:
|
||||
intercom_init();
|
||||
update_send_cmd(0);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void temp_sensor_tick() {
|
||||
uint8_t i = 0;
|
||||
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
|
||||
PRR0 &= ~MASK(PRSPI);
|
||||
#endif
|
||||
|
||||
SPCR = MASK(MSTR) | MASK(SPE) | MASK(SPR0);
|
||||
|
||||
// enable TT_MAX6675
|
||||
WRITE(SS, 0);
|
||||
|
||||
// ensure 100ns delay - a bit extra is fine
|
||||
delay(1);
|
||||
|
||||
// read MSB
|
||||
SPDR = 0;
|
||||
for (;(SPSR & MASK(SPIF)) == 0;);
|
||||
temp = SPDR;
|
||||
temp <<= 8;
|
||||
|
||||
// read LSB
|
||||
SPDR = 0;
|
||||
for (;(SPSR & MASK(SPIF)) == 0;);
|
||||
temp |= SPDR;
|
||||
|
||||
// disable TT_MAX6675
|
||||
WRITE(SS, 1);
|
||||
|
||||
temp_sensors_runtime[i].temp_flags = 0;
|
||||
if ((temp & 0x8002) == 0) {
|
||||
// got "device id"
|
||||
temp_sensors_runtime[i].temp_flags |= PRESENT;
|
||||
if (temp & 4) {
|
||||
// thermocouple open
|
||||
temp_sensors_runtime[i].temp_flags |= TCOPEN;
|
||||
}
|
||||
else {
|
||||
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
|
||||
case TT_THERMISTOR:
|
||||
do {
|
||||
uint8_t j;
|
||||
//Read current temperature
|
||||
temp = analog_read(temp_sensors[i].temp_pin);
|
||||
|
||||
//Calculate real temperature based on lookup table
|
||||
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[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 (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
|
||||
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;
|
||||
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
|
||||
break;
|
||||
#endif /* TEMP_AD595 */
|
||||
|
||||
#ifdef TEMP_PT100
|
||||
case TT_PT100:
|
||||
#warning TODO: PT100 code
|
||||
break
|
||||
#endif /* TEMP_PT100 */
|
||||
|
||||
#ifdef GEN3
|
||||
case TT_INTERCOM:
|
||||
temp = get_read_cmd() << 2;
|
||||
|
||||
start_send();
|
||||
|
||||
temp_sensors_runtime[i].next_read_time = 0;
|
||||
|
||||
break;
|
||||
#endif /* GEN3 */
|
||||
}
|
||||
temp_sensors_runtime[i].last_read_temp = temp;
|
||||
|
||||
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 {
|
||||
temp_sensors_runtime[i].temp_residency = 0;
|
||||
}
|
||||
|
||||
if (temp_sensors[i].heater_index < NUM_HEATERS) {
|
||||
heater_tick(temp_sensors[i].heater_index, temp_sensors_runtime[i].last_read_temp, temp_sensors_runtime[i].target_temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t temp_achieved() {
|
||||
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
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef _TEMP_H
|
||||
#define _TEMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
NOTES
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#define temp_tick temp_sensor_tick
|
||||
|
||||
void temp_init(void);
|
||||
|
||||
void temp_sensor_tick(void);
|
||||
|
||||
uint8_t temp_achieved(void);
|
||||
|
||||
void temp_set(uint8_t index, uint16_t temperature);
|
||||
uint16_t temp_get(uint8_t index);
|
||||
|
||||
void temp_print(uint8_t index);
|
||||
|
||||
uint16_t temp_read(uint8_t index);
|
||||
|
||||
#endif /* _TIMER_H */
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
#include "watchdog.h"
|
||||
|
||||
#ifdef USE_WATCHDOG
|
||||
|
||||
#include <avr/wdt.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "arduino.h"
|
||||
#include "serial.h"
|
||||
|
||||
volatile uint8_t wd_flag = 0;
|
||||
|
||||
// uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
|
||||
// void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
|
||||
// void get_mcusr(void) {
|
||||
// mcusr_mirror = MCUSR;
|
||||
// MCUSR = 0;
|
||||
// wdt_disable();
|
||||
// }
|
||||
|
||||
ISR(WDT_vect) {
|
||||
// watchdog has tripped- no main loop activity for 0.5s, probably a bad thing
|
||||
// if watchdog fires again, we will reset
|
||||
// perhaps we should do something more intelligent in this interrupt?
|
||||
wd_flag |= 1;
|
||||
}
|
||||
|
||||
void wd_init() {
|
||||
// check if we were reset by the watchdog
|
||||
// if (mcusr_mirror & MASK(WDRF))
|
||||
// serial_writestr_P(PSTR("Watchdog Reset!\n"));
|
||||
|
||||
// 0.25s timeout, interrupt and system reset
|
||||
wdt_enable(WDTO_500MS);
|
||||
WDTCSR |= MASK(WDIE);
|
||||
}
|
||||
|
||||
void wd_reset() {
|
||||
wdt_reset();
|
||||
if (wd_flag) {
|
||||
WDTCSR |= MASK(WDIE);
|
||||
wd_flag &= ~1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* USE_WATCHDOG */
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef _WATCHDOG_H
|
||||
#define _WATCHDOG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_WATCHDOG
|
||||
|
||||
// initialize
|
||||
void wd_init(void) __attribute__ ((cold));
|
||||
|
||||
// reset timeout- must be called periodically or we reboot
|
||||
void wd_reset(void);
|
||||
|
||||
// notable lack of disable function
|
||||
|
||||
#else /* USE_WATCHDOG */
|
||||
|
||||
#define wd_init() /* empty */
|
||||
#define wd_reset() /* empty */
|
||||
|
||||
#endif /* USE_WATCHDOG */
|
||||
#endif /* _WATCHDOG_H */
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#if defined (__AVR_ATmega168__)
|
||||
FUSES = {
|
||||
.low = FUSE_CKSEL3 & FUSE_SUT0,
|
||||
.high = FUSE_SPIEN,
|
||||
.extended = FUSE_BOOTSZ1 & FUSE_BOOTSZ0,
|
||||
};
|
||||
#elif defined (__AVR_ATmega328P__)
|
||||
FUSES = {
|
||||
.low = FUSE_CKSEL3 & FUSE_SUT0,
|
||||
.high = FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTSZ1,
|
||||
.extended = EFUSE_DEFAULT,
|
||||
};
|
||||
#elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644P__)
|
||||
FUSES = {
|
||||
.low = FUSE_CKSEL3 & FUSE_SUT0,
|
||||
.high = FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTSZ1,
|
||||
.extended = EFUSE_DEFAULT,
|
||||
};
|
||||
#elif defined (__AVR_ATmega1280__)
|
||||
FUSES = {
|
||||
.low = FUSE_CKSEL3 & FUSE_SUT0,
|
||||
.high = FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTSZ1,
|
||||
.extended = EFUSE_DEFAULT,
|
||||
};
|
||||
#else
|
||||
#warning No fuse definitions for this chip in fuses.h!
|
||||
#endif
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
#include "intercom.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "delay.h"
|
||||
|
||||
#ifdef GEN3
|
||||
#define INTERCOM_BAUD 57600
|
||||
|
||||
#define enable_transmit() do { WRITE(TX_ENABLE_PIN,1); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
#define disable_transmit() do { WRITE(TX_ENABLE_PIN,0); WRITE(RX_ENABLE_PIN,0); } while(0)
|
||||
|
||||
/*
|
||||
Defines a super simple intercom interface using the RS485 modules
|
||||
|
||||
Host will say: START1 START2 PWM_CMD PWM_CHK
|
||||
Extruder will reply: START1 START2 TMP_CMD TMP_CHK
|
||||
|
||||
CHK = 255-CMD, if they match do the work, if not, ignore this packet
|
||||
|
||||
in a loop
|
||||
*/
|
||||
|
||||
|
||||
#define START1 0xAA
|
||||
#define START2 0x55
|
||||
|
||||
typedef enum {
|
||||
SEND_START1,
|
||||
SEND_START2,
|
||||
SEND_CMD,
|
||||
SEND_CHK,
|
||||
SEND_DONE,
|
||||
|
||||
READ_START1,
|
||||
READ_START2,
|
||||
READ_CMD,
|
||||
READ_CHK,
|
||||
} intercom_state_e;
|
||||
|
||||
|
||||
intercom_state_e state = READ_START1;
|
||||
uint8_t cmd, chk, send_cmd, read_cmd;
|
||||
|
||||
void intercom_init(void)
|
||||
{
|
||||
#ifdef HOST
|
||||
#if INTERCOM_BAUD > 38401
|
||||
UCSR1A = MASK(U2X1);
|
||||
UBRR1 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5);
|
||||
#else
|
||||
UCSR1A = 0;
|
||||
UBRR1 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5);
|
||||
#endif
|
||||
UCSR1B = MASK(RXEN1) | MASK(TXEN1);
|
||||
UCSR1C = MASK(UCSZ11) | MASK(UCSZ10);
|
||||
|
||||
UCSR1B |= MASK(RXCIE1) | MASK(TXCIE1);
|
||||
#else
|
||||
#if INTERCOM_BAUD > 38401
|
||||
UCSR0A = MASK(U2X0);
|
||||
UBRR0 = (((F_CPU / 8) / INTERCOM_BAUD) - 0.5);
|
||||
#else
|
||||
UCSR0A = 0;
|
||||
UBRR0 = (((F_CPU / 16) / INTERCOM_BAUD) - 0.5);
|
||||
#endif
|
||||
UCSR0B = MASK(RXEN0) | MASK(TXEN0);
|
||||
UCSR0C = MASK(UCSZ01) | MASK(UCSZ00);
|
||||
|
||||
UCSR0B |= MASK(RXCIE0) | MASK(TXCIE0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_send_cmd(uint8_t new_send_cmd) {
|
||||
send_cmd = new_send_cmd;
|
||||
}
|
||||
|
||||
uint8_t get_read_cmd(void) {
|
||||
return read_cmd;
|
||||
}
|
||||
|
||||
static void write_byte(uint8_t val) {
|
||||
#ifdef HOST
|
||||
UDR1 = val;
|
||||
#else
|
||||
UDR0 = val;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void start_send(void) {
|
||||
state = SEND_START1;
|
||||
enable_transmit();
|
||||
delay_us(15);
|
||||
//Enable interrupts so we can send next characters
|
||||
#ifdef HOST
|
||||
UCSR1B |= MASK(UDRIE1);
|
||||
#else
|
||||
UCSR0B |= MASK(UDRIE0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void finish_send(void) {
|
||||
state = READ_START1;
|
||||
disable_transmit();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Interrupts, UART 0 for mendel
|
||||
*/
|
||||
#ifdef HOST
|
||||
ISR(USART1_RX_vect)
|
||||
#else
|
||||
ISR(USART_RX_vect)
|
||||
#endif
|
||||
{
|
||||
static uint8_t c;
|
||||
|
||||
#ifdef HOST
|
||||
c = UDR1;
|
||||
UCSR1A &= ~MASK(FE1) & ~MASK(DOR1) & ~MASK(UPE1);
|
||||
#else
|
||||
c = UDR0;
|
||||
UCSR0A &= ~MASK(FE0) & ~MASK(DOR0) & ~MASK(UPE0);
|
||||
#endif
|
||||
|
||||
if (state >= READ_START1) {
|
||||
|
||||
switch(state) {
|
||||
case READ_START1:
|
||||
if (c == START1) state = READ_START2;
|
||||
break;
|
||||
case READ_START2:
|
||||
if (c == START2) state = READ_CMD;
|
||||
else state = READ_START1;
|
||||
break;
|
||||
case READ_CMD:
|
||||
cmd = c;
|
||||
state = READ_CHK;
|
||||
break;
|
||||
case READ_CHK:
|
||||
chk = c;
|
||||
|
||||
if (chk == 255 - cmd) {
|
||||
//Values are correct, do something useful
|
||||
WRITE(DEBUG_LED,1);
|
||||
read_cmd = cmd;
|
||||
#ifdef EXTRUDER
|
||||
start_send();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
state = READ_START1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef HOST
|
||||
ISR(USART1_TX_vect)
|
||||
#else
|
||||
ISR(USART_TX_vect)
|
||||
#endif
|
||||
{
|
||||
if (state == SEND_DONE) {
|
||||
finish_send();
|
||||
|
||||
|
||||
#ifdef HOST
|
||||
UCSR1B &= ~MASK(TXCIE1);
|
||||
#else
|
||||
UCSR0B &= ~MASK(TXCIE0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HOST
|
||||
ISR(USART1_UDRE_vect)
|
||||
#else
|
||||
ISR(USART_UDRE_vect)
|
||||
#endif
|
||||
{
|
||||
switch(state) {
|
||||
case SEND_START1:
|
||||
write_byte(START1);
|
||||
state = SEND_START2;
|
||||
break;
|
||||
case SEND_START2:
|
||||
write_byte(START2);
|
||||
state = SEND_CMD;
|
||||
break;
|
||||
case SEND_CMD:
|
||||
write_byte(send_cmd);
|
||||
state = SEND_CHK;
|
||||
break;
|
||||
case SEND_CHK:
|
||||
write_byte(255 - send_cmd);
|
||||
state = SEND_DONE;
|
||||
#ifdef HOST
|
||||
UCSR1B &= ~MASK(UDRIE1);
|
||||
UCSR1B |= MASK(TXCIE1);
|
||||
#else
|
||||
UCSR0B &= ~MASK(UDRIE0);
|
||||
UCSR0B |= MASK(TXCIE0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* GEN3 */
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef _INTERCOM_H
|
||||
#define _INTERCOM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// initialise serial subsystem
|
||||
void intercom_init(void);
|
||||
|
||||
//Update the message we are sending over intercom
|
||||
void update_send_cmd(uint8_t new_send_cmd);
|
||||
|
||||
void start_send(void);
|
||||
|
||||
//Read the message we are receiving over intercom
|
||||
uint8_t get_read_cmd(void);
|
||||
|
||||
#endif /* _INTERCOM_H */
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#include "pinio.h"
|
||||
|
||||
void power_off() {
|
||||
#ifdef X_ENABLE_PIN
|
||||
x_disable();
|
||||
#endif
|
||||
#ifdef Y_ENABLE_PIN
|
||||
y_disable();
|
||||
#endif
|
||||
#ifdef Z_ENABLE_PIN
|
||||
z_disable();
|
||||
#endif
|
||||
|
||||
#ifdef STEPPER_ENABLE_PIN
|
||||
WRITE(STEPPER_ENABLE_PIN, STEPPER_ENABLE_INVERT ^ 1)
|
||||
#endif
|
||||
#ifdef PS_ON_PIN
|
||||
SET_INPUT(PS_ON_PIN);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
#ifndef _PINIO_H
|
||||
#define _PINIO_H
|
||||
|
||||
#ifndef X_INVERT_DIR
|
||||
#define X_INVERT_DIR 0
|
||||
#endif
|
||||
#ifndef X_INVERT_MIN
|
||||
#define X_INVERT_MIN 0
|
||||
#endif
|
||||
#ifndef X_INVERT_MAX
|
||||
#define X_INVERT_MAX 0
|
||||
#endif
|
||||
#ifndef X_INVERT_ENABLE
|
||||
#define X_INVERT_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef Y_INVERT_DIR
|
||||
#define Y_INVERT_DIR 0
|
||||
#endif
|
||||
#ifndef Y_INVERT_MIN
|
||||
#define Y_INVERT_MIN 0
|
||||
#endif
|
||||
#ifndef Y_INVERT_MAX
|
||||
#define Y_INVERT_MAX 0
|
||||
#endif
|
||||
#ifndef Y_INVERT_ENABLE
|
||||
#define Y_INVERT_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef Z_INVERT_DIR
|
||||
#define Z_INVERT_DIR 0
|
||||
#endif
|
||||
#ifndef Z_INVERT_MIN
|
||||
#define Z_INVERT_MIN 0
|
||||
#endif
|
||||
#ifndef Z_INVERT_MAX
|
||||
#define Z_INVERT_MAX 0
|
||||
#endif
|
||||
#ifndef Z_INVERT_ENABLE
|
||||
#define Z_INVERT_ENABLE 0
|
||||
#endif
|
||||
|
||||
#ifndef E_INVERT_DIR
|
||||
#define E_INVERT_DIR 0
|
||||
#endif
|
||||
|
||||
#ifndef STEPPER_ENABLE_INVERT
|
||||
#define STEPPER_ENABLE_INVERT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
Power
|
||||
*/
|
||||
|
||||
#ifdef STEPPER_ENABLE_PIN
|
||||
#define power_on() do { WRITE(STEPPER_ENABLE_PIN, STEPPER_ENABLE_INVERT); SET_OUTPUT(STEPPER_ENABLE_PIN); } while (0)
|
||||
#elif defined PS_ON_PIN
|
||||
#define power_on() do { WRITE(PS_ON_PIN, 0); SET_OUTPUT(PS_ON_PIN); } while (0)
|
||||
#else
|
||||
#define power_on() do { } while (0)
|
||||
#endif
|
||||
|
||||
void power_off(void);
|
||||
|
||||
/*
|
||||
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 ^ X_INVERT_DIR)
|
||||
#define x_min() (READ(X_MIN_PIN)?(X_INVERT_MIN ^ 1):X_INVERT_DIR)
|
||||
#ifdef X_MAX_PIN
|
||||
#define x_max() (READ(X_MAX_PIN)?(X_INVERT_MAX ^ 1):X_INVERT_MAX)
|
||||
#else
|
||||
#define x_max() (0)
|
||||
#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 ^ Y_INVERT_DIR)
|
||||
#define y_min() (READ(Y_MIN_PIN)?(Y_INVERT_MIN ^ 1):Y_INVERT_MIN)
|
||||
#ifdef Y_MAX_PIN
|
||||
#define y_max() (READ(Y_MAX_PIN)?(Y_INVERT_MAX ^ 1):Y_INVERT_MAX)
|
||||
#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 ^ Z_INVERT_DIR)
|
||||
#define z_min() (READ(Z_MIN_PIN)?(Z_INVERT_MIN ^ 1):Z_INVERT_MIN)
|
||||
#ifdef Z_MAX_PIN
|
||||
#define z_max() (READ(Z_MAX_PIN)?(Z_INVERT_MAX ^ 1):Z_INVERT_MAX)
|
||||
#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 ^ E_INVERT_DIR)
|
||||
|
||||
/*
|
||||
End Step - All Steppers
|
||||
(so we don't have to delay in interrupt context)
|
||||
*/
|
||||
|
||||
#ifndef DC_EXTRUDER
|
||||
#define unstep() do { _x_step(0); _y_step(0); _z_step(0); _e_step(0); } while (0)
|
||||
#else
|
||||
#define unstep() do { _x_step(0); _y_step(0); _z_step(0); } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
Stepper Enable Pins
|
||||
*/
|
||||
|
||||
#ifdef X_ENABLE_PIN
|
||||
#define x_enable() do { WRITE(X_ENABLE_PIN, X_INVERT_ENABLE); SET_OUTPUT(X_ENABLE_PIN); } while (0)
|
||||
#define x_disable() do { WRITE(X_ENABLE_PIN, X_INVERT_ENABLE ^ 1); SET_OUTPUT(X_ENABLE_PIN); } while (0)
|
||||
#else
|
||||
#define x_enable() do { } while (0)
|
||||
#define x_disable() do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef Y_ENABLE_PIN
|
||||
#define y_enable() do { WRITE(Y_ENABLE_PIN, Y_INVERT_ENABLE); SET_OUTPUT(Y_ENABLE_PIN); } while (0)
|
||||
#define y_disable() do { WRITE(Y_ENABLE_PIN, Y_INVERT_ENABLE ^ 1); SET_OUTPUT(Y_ENABLE_PIN); } while (0)
|
||||
#else
|
||||
#define y_enable() do { } while (0)
|
||||
#define y_disable() do { } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef Z_ENABLE_PIN
|
||||
#define z_enable() do { WRITE(Z_ENABLE_PIN, Z_INVERT_ENABLE); SET_OUTPUT(Z_ENABLE_PIN); } while (0)
|
||||
#define z_disable() do { WRITE(Z_ENABLE_PIN, Z_INVERT_ENABLE ^ 1); SET_OUTPUT(Z_ENABLE_PIN); } while (0)
|
||||
#else
|
||||
#define z_enable() do { } while (0)
|
||||
#define z_disable() do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif /* _PINIO_H */
|
||||
Loading…
Reference in New Issue