diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a050f1b --- /dev/null +++ b/Makefile @@ -0,0 +1,637 @@ +# Makefile for ATmegaBOOT +# E.Lins, 18.7.2005 +# $Id$ +# +# Instructions +# +# To make bootloader .hex file: +# make diecimila +# make lilypad +# make ng +# etc... +# +# To burn bootloader .hex file: +# make diecimila_isp +# make lilypad_isp +# make ng_isp +# etc... +# +# Edit History +# 201303xx: WestfW: Major Makefile restructuring. +# Allows options on Make command line "make xx LED=B3" +# (see also pin_defs.h) +# Divide into "chip" targets and "board" targets. +# Most boards are (recursive) board targets with options. +# Move isp target to separate makefile (fixes m8 EFUSE) +# Some (many) targets will now be rebuilt when not +# strictly necessary, so that options will be included. +# (any "make" with options will always compile.) +# Set many variables with ?= so they can be overridden +# Use arduinoISP settings as default for ISP targets +# + +#---------------------------------------------------------------------- +# +# program name should not be changed... +PROGRAM = optiboot + +# The default behavior is to build using tools that are in the users +# current path variables, but we can also build using an installed +# Arduino user IDE setup, or the Arduino source tree. +# Uncomment this next lines to build within the arduino environment, +# using the arduino-included avrgcc toolset (mac and pc) +# ENV ?= arduino +# ENV ?= arduinodev +# OS ?= macosx +# OS ?= windows + +# export symbols to recursive makes (for ISP) +export + +# defaults +MCU_TARGET = atmega168 +LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe + +# Build environments +# Start of some ugly makefile-isms to allow optiboot to be built +# in several different environments. See the README.TXT file for +# details. + +# default +fixpath = $(1) + +ifeq ($(ENV), arduino) +# For Arduino, we assume that we're connected to the optiboot directory +# included with the arduino distribution, which means that the full set +# of avr-tools are "right up there" in standard places. +TOOLROOT = ../../../tools +GCCROOT = $(TOOLROOT)/avr/bin/ + +ifeq ($(OS), windows) +# On windows, SOME of the tool paths will need to have backslashes instead +# of forward slashes (because they use windows cmd.exe for execution instead +# of a unix/mingw shell?) We also have to ensure that a consistent shell +# is used even if a unix shell is installed (ie as part of WINAVR) +fixpath = $(subst /,\,$1) +SHELL = cmd.exe +endif + +else ifeq ($(ENV), arduinodev) +# Arduino IDE source code environment. Use the unpacked compilers created +# by the build (you'll need to do "ant build" first.) +ifeq ($(OS), macosx) +TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools +endif +ifeq ($(OS), windows) +TOOLROOT = ../../../../build/windows/work/hardware/tools +endif + +GCCROOT = $(TOOLROOT)/avr/bin/ +AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf + +else +GCCROOT = +AVRDUDE_CONF = +endif + +STK500 = "C:\Program Files\Atmel\AVR Tools\STK500\Stk500.exe" +STK500-1 = $(STK500) -e -d$(MCU_TARGET) -pf -vf -if$(PROGRAM)_$(TARGET).hex \ + -lFF -LFF -f$(HFUSE)$(LFUSE) -EF8 -ms -q -cUSB -I200kHz -s -wt +STK500-2 = $(STK500) -d$(MCU_TARGET) -ms -q -lCF -LCF -cUSB -I200kHz -s -wt +# +# End of build environment code. + + +OBJ = $(PROGRAM).o +OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls + +DEFS = +LIBS = + +CC = $(GCCROOT)avr-gcc + +# Override is only needed by avr-lib build system. + +override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS) +override LDFLAGS = $(LDSECTIONS) -Wl,--relax -nostartfiles -nostdlib +#-Wl,--gc-sections + +OBJCOPY = $(GCCROOT)avr-objcopy +OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump) + +SIZE = $(GCCROOT)avr-size + +# +# Make command-line Options. +# Permit commands like "make atmega328 LED_START_FLASHES=10" to pass the +# appropriate parameters ("-DLED_START_FLASHES=10") to gcc +# + +ifdef BAUD_RATE +BAUD_RATE_CMD = -DBAUD_RATE=$(BAUD_RATE) +dummy = FORCE +else +BAUD_RATE_CMD = -DBAUD_RATE=115200 +endif + +ifdef LED_START_FLASHES +LED_START_FLASHES_CMD = -DLED_START_FLASHES=$(LED_START_FLASHES) +dummy = FORCE +else +LED_START_FLASHES_CMD = -DLED_START_FLASHES=3 +endif + +# BIG_BOOT: Include extra features, up to 1K. +ifdef BIGBOOT +BIGBOOT_CMD = -DBIGBOOT=1 +dummy = FORCE +endif + +ifdef SOFT_UART +SOFT_UART_CMD = -DSOFT_UART=1 +dummy = FORCE +endif + +ifdef LED_DATA_FLASH +LED_DATA_FLASH_CMD = -DLED_DATA_FLASH=1 +dummy = FORCE +endif + +ifdef LED +LED_CMD = -DLED=$(LED) +dummy = FORCE +endif + +ifdef SINGLESPEED +SSCMD = -DSINGLESPEED=1 +endif + +COMMON_OPTIONS = $(BAUD_RATE_CMD) $(LED_START_FLASHES_CMD) $(BIGBOOT_CMD) +COMMON_OPTIONS += $(SOFT_UART_CMD) $(LED_DATA_FLASH_CMD) $(LED_CMD) $(SSCMD) + +#UART is handled separately and only passed for devices with more than one. +ifdef UART +UARTCMD = -DUART=$(UART) +endif + +# Not supported yet +# ifdef SUPPORT_EEPROM +# SUPPORT_EEPROM_CMD = -DSUPPORT_EEPROM +# dummy = FORCE +# endif + +# Not supported yet +# ifdef TIMEOUT_MS +# TIMEOUT_MS_CMD = -DTIMEOUT_MS=$(TIMEOUT_MS) +# dummy = FORCE +# endif +# + +#--------------------------------------------------------------------------- +# "Chip-level Platform" targets. +# A "Chip-level Platform" compiles for a particular chip, but probably does +# not have "standard" values for things like clock speed, LED pin, etc. +# Makes for chip-level platforms should usually explicitly define their +# options like: "make atmega1285 AVR_FREQ=16000000L LED=D0" +#--------------------------------------------------------------------------- +# +# Note about fuses: +# the efuse should really be 0xf8; since, however, only the lower +# three bits of that byte are used on the atmega168, avrdude gets +# confused if you specify 1's for the higher bits, see: +# http://tinker.it/now/2007/02/24/the-tale-of-avrdude-atmega168-and-extended-bits-fuses/ +# +# similarly, the lock bits should be 0xff instead of 0x3f (to +# unlock the bootloader section) and 0xcf instead of 0x2f (to +# lock it), but since the high two bits of the lock byte are +# unused, avrdude would get confused. +#--------------------------------------------------------------------------- +# + +# Test platforms +# Virtual boot block test +virboot328: TARGET = atmega328 +virboot328: MCU_TARGET = atmega328p +virboot328: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT' +virboot328: AVR_FREQ ?= 16000000L +virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe +virboot328: $(PROGRAM)_atmega328.hex +virboot328: $(PROGRAM)_atmega328.lst + +# Diecimila, Duemilanove with m168, and NG use identical bootloaders +# Call it "atmega168" for generality and clarity, keep "diecimila" for +# backward compatibility of makefile +# +atmega168: TARGET = atmega168 +atmega168: MCU_TARGET = atmega168 +atmega168: CFLAGS += $(COMMON_OPTIONS) +atmega168: AVR_FREQ ?= 16000000L +atmega168: $(PROGRAM)_atmega168.hex +atmega168: $(PROGRAM)_atmega168.lst + +atmega168_isp: atmega168 +atmega168_isp: TARGET = atmega168 +# 2.7V brownout +atmega168_isp: HFUSE ?= DD +# Low power xtal (16MHz) 16KCK/14CK+65ms +atmega168_isp: LFUSE ?= FF +# 512 byte boot +atmega168_isp: EFUSE ?= 04 +atmega168_isp: isp + +atmega328: TARGET = atmega328 +atmega328: MCU_TARGET = atmega328p +atmega328: CFLAGS += $(COMMON_OPTIONS) +atmega328: AVR_FREQ ?= 16000000L +atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7c00 -Wl,--section-start=.version=0x7ffe +atmega328: $(PROGRAM)_atmega328.hex +atmega328: $(PROGRAM)_atmega328.lst + +atmega328_isp: atmega328 +atmega328_isp: TARGET = atmega328 +atmega328_isp: MCU_TARGET = atmega328p +# 512 byte boot, SPIEN +atmega328_isp: HFUSE ?= DE +# Low power xtal (16MHz) 16KCK/14CK+65ms +atmega328_isp: LFUSE ?= FF +# 2.7V brownout +atmega328_isp: EFUSE ?= FD +atmega328_isp: isp + +atmega644p: TARGET = atmega644p +atmega644p: MCU_TARGET = atmega644p +atmega644p: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(LED_CMD) +atmega644p: AVR_FREQ ?= 16000000L +atmega644p: LDSECTIONS = -Wl,--section-start=.text=0xfc00 -Wl,--section-start=.version=0xfffe +atmega644p: CFLAGS += $(UARTCMD) +atmega644p: $(PROGRAM)_atmega644p.hex +atmega644p: $(PROGRAM)_atmega644p.lst + +atmega1284: TARGET = atmega1284p +atmega1284: MCU_TARGET = atmega1284p +atmega1284: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(LED_CMD) +atmega1284: AVR_FREQ ?= 16000000L +atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe +atmega1284: CFLAGS += $(UARTCMD) +atmega1284: $(PROGRAM)_atmega1284p.hex +atmega1284: $(PROGRAM)_atmega1284p.lst + +atmega1284p: atmega1284 + +atmega1284_isp: atmega1284 +atmega1284_isp: TARGET = atmega1284p +atmega1284_isp: MCU_TARGET = atmega1284p +# 1024 byte boot +atmega1284_isp: HFUSE ?= DE +# Full Swing xtal (16MHz) 16KCK/14CK+65ms +atmega1284_isp: LFUSE ?= F7 +# 2.7V brownout +atmega1284_isp: EFUSE ?= FD +atmega1284_isp: isp + +#Atmega1280 +atmega1280: MCU_TARGET = atmega1280 +atmega1280: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD) +atmega1280: AVR_FREQ ?= 16000000L +atmega1280: LDSECTIONS = -Wl,--section-start=.text=0x1fc00 -Wl,--section-start=.version=0x1fffe +atmega1280: $(PROGRAM)_atmega1280.hex +atmega1280: $(PROGRAM)_atmega1280.lst + + +# ATmega8 +# +atmega8: TARGET = atmega8 +atmega8: MCU_TARGET = atmega8 +atmega8: CFLAGS += $(COMMON_OPTIONS) +atmega8: AVR_FREQ ?= 16000000L +atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe +atmega8: $(PROGRAM)_atmega8.hex +atmega8: $(PROGRAM)_atmega8.lst + +atmega8_isp: atmega8 +atmega8_isp: TARGET = atmega8 +atmega8_isp: MCU_TARGET = atmega8 +# SPIEN, CKOPT (for full swing xtal), Bootsize=512B +atmega8_isp: HFUSE ?= CC +# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms +atmega8_isp: LFUSE ?= BF +atmega8_isp: isp + +# ATmega88 +# +atmega88: TARGET = atmega88 +atmega88: MCU_TARGET = atmega88 +atmega88: CFLAGS += $(COMMON_OPTIONS) +atmega88: AVR_FREQ ?= 16000000L +atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe +atmega88: $(PROGRAM)_atmega88.hex +atmega88: $(PROGRAM)_atmega88.lst + +atmega88_isp: atmega88 +atmega88_isp: TARGET = atmega88 +atmega88_isp: MCU_TARGET = atmega88 +# 2.7V brownout +atmega88_isp: HFUSE ?= DD +# Low power xtal (16MHz) 16KCK/14CK+65ms +atemga88_isp: LFUSE ?= FF +# 512 byte boot +atmega88_isp: EFUSE ?= 04 +atmega88_isp: isp + +atmega32: TARGET = atmega32 +atmega32: MCU_TARGET = atmega32 +atmega32: CFLAGS += $(COMMON_OPTIONS) +atmega32: AVR_FREQ ?= 11059200L +atmega32: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe +atmega32: $(PROGRAM)_atmega32.hex +atmega32: $(PROGRAM)_atmega32.lst + +atmega32_isp: atmega32 +atmega32_isp: TARGET = atmega32 +atmega32_isp: MCU_TARGET = atmega32 +# No OCD or JTAG, SPIEN, CKOPT (for full swing xtal), Bootsize=512B +atmega32_isp: HFUSE ?= CE +# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms +atemga32_isp: LFUSE ?= BF +atmega32_isp: isp + + + +#--------------------------------------------------------------------------- +# "Board-level Platform" targets. +# A "Board-level Platform" implies a manufactured platform with a particular +# AVR_FREQ, LED, and so on. Parameters are not particularly changable from +# the "make" command line. +# Most of the board-level platform builds should envoke make recursively +# appropriate specific options +#--------------------------------------------------------------------------- +# 20MHz clocked platforms +# +# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue) +# + +pro20: TARGET = pro_20mhz +pro20: CHIP = atmega168 +pro20: + $(MAKE) atmega168 AVR_FREQ=20000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +pro20_isp: pro20 +pro20_isp: TARGET = pro_20mhz +# 2.7V brownout +pro20_isp: HFUSE ?= DD +# Full swing xtal (20MHz) 258CK/14CK+4.1ms +pro20_isp: LFUSE ?= C6 +# 512 byte boot +pro20_isp: EFUSE ?= 04 +pro20_isp: isp + +# 16MHz clocked platforms +# +# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue) +# + +pro16: TARGET = pro_16MHz +pro16: CHIP = atmega168 +pro16: + $(MAKE) $(CHIP) AVR_FREQ=16000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +pro16_isp: pro16 +pro16_isp: TARGET = pro_16MHz +# 2.7V brownout +pro16_isp: HFUSE ?= DD +# Full swing xtal (20MHz) 258CK/14CK+4.1ms +pro16_isp: LFUSE ?= C6 +# 512 byte boot +pro16_isp: EFUSE ?= 04 +pro16_isp: isp + +diecimila: TARGET = diecimila +diecimila: CHIP = atmega168 +diecimila: + $(MAKE) $(CHIP) AVR_FREQ=16000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +diecimila_isp: diecimila +diecimila_isp: TARGET = diecimila +# 2.7V brownout +diecimila_isp: HFUSE ?= DD +# Low power xtal (16MHz) 16KCK/14CK+65ms +diecimila_isp: LFUSE ?= FF +# 512 byte boot +diecimila_isp: EFUSE ?= 04 +diecimila_isp: isp + +# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions +# +sanguino: TARGET = $@ +sanguino: CHIP = atmega644p +sanguino: + $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=B0 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +sanguino_isp: sanguino +sanguino_isp: TARGET = sanguino +sanguino_isp: MCU_TARGET = atmega644p +# 1024 byte boot +sanguino_isp: HFUSE ?= DE +# Full swing xtal (16MHz) 16KCK/14CK+65ms +sanguino_isp: LFUSE ?= F7 +# 2.7V brownout +sanguino_isp: EFUSE ?= FD +sanguino_isp: isp + +mighty1284: TARGET = $@ +mighty1284: CHIP = atmega1284p +mighty1284: + $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=D7 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +mighty1284_isp: mighty1284 +mighty1284_isp: TARGET = mighty1284 +mighty1284_isp: MCU_TARGET = atmega1284p +# 1024 byte boot +mighty1284_isp: HFUSE ?= DE +# Full swing xtal (16MHz) 16KCK/14CK+65ms +mighty1284_isp: LFUSE ?= F7 +# 2.7V brownout +mighty1284_isp: EFUSE ?= FD +mighty1284_isp: isp + +bobuino: TARGET = $@ +bobuino: CHIP = atmega1284p +bobuino: + $(MAKE) $(CHIP) AVR_FREQ=16000000L LED=B5 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +bobuino_isp: bobuino +bobuino_isp: TARGET = bobuino +bobuino_isp: MCU_TARGET = atmega1284p +# 1024 byte boot +bobuino_isp: HFUSE ?= DE +# Full swing xtal (16MHz) 16KCK/14CK+65ms +bobuino_isp: LFUSE ?= F7 +# 2.7V brownout +bobuino_isp: EFUSE ?= FD +bobuino_isp: isp + +# MEGA1280 Board (this is different from the atmega1280 chip platform) +# Mega has a minimum boot size of 1024 bytes, so enable extra functions +# Note that optiboot does not (can not) work on the MEGA2560 +#mega: TARGET = atmega1280 +mega1280: atmega1280 + + +mega1280_isp: mega1280 +mega1280_isp: TARGET = atmega1280 +mega1280_isp: MCU_TARGET = atmega1280 +# 1024 byte boot +mega1280_isp: HFUSE ?= DE +# Low power xtal (16MHz) 16KCK/14CK+65ms +mega1280_isp: LFUSE ?= FF +# 2.7V brownout; wants F5 for some reason... +mega1280_isp: EFUSE ?= F5 +mega1280_isp: isp + +# 8MHz clocked platforms +# +# These are capable of 115200 baud +# Note that "new" Arduinos with an AVR as USB/Serial converter will NOT work +# with an 8MHz target Arduino. The bitrate errors are in opposite directions, +# and total too large a number. +# + +lilypad: TARGET = $@ +lilypad: CHIP = atmega168 +lilypad: + $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +lilypad_isp: lilypad +lilypad_isp: TARGET = lilypad +# 2.7V brownout +lilypad_isp: HFUSE ?= DD +# Internal 8MHz osc (8MHz) Slow rising power +lilypad_isp: LFUSE ?= E2 +# 512 byte boot +lilypad_isp: EFUSE ?= 04 +lilypad_isp: isp + +# lilypad_resonator is the same as a 8MHz lilypad, except for fuses. +lilypad_resonator: lilypad + +lilypad_resonator_isp: lilypad +lilypad_resonator_isp: TARGET = lilypad +# 2.7V brownout +lilypad_resonator_isp: HFUSE ?= DD +# Full swing xtal (20MHz) 258CK/14CK+4.1ms +lilypad_resonator_isp: LFUSE ?= C6 +# 512 byte boot +lilypad_resonator_isp: EFUSE ?= 04 +lilypad_resonator_isp: isp + +pro8: TARGET = pro_8MHz +pro8: CHIP = atmega168 +pro8: + $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +pro8_isp: pro8 +pro8_isp: TARGET = pro_8MHz +# 2.7V brownout +pro8_isp: HFUSE ?= DD +# Full swing xtal (20MHz) 258CK/14CK+4.1ms +pro8_isp: LFUSE ?= C6 +# 512 byte boot +pro8_isp: EFUSE ?= 04 +pro8_isp: isp + +atmega328_pro8: TARGET = atmega328_pro_8MHz +atmega328_pro8: CHIP = atmega328 +atmega328_pro8: + $(MAKE) $(CHIP) AVR_FREQ=8000000L LED_START_FLASHES=3 + mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex + mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst + +atmega328_pro8_isp: atmega328_pro8 +atmega328_pro8_isp: TARGET = atmega328_pro_8MHz +atmega328_pro8_isp: MCU_TARGET = atmega328p +# 512 byte boot, SPIEN +atmega328_pro8_isp: HFUSE ?= DE +# Low power xtal (16MHz) 16KCK/14CK+65ms +atmega328_pro8_isp: LFUSE ?= FF +# 2.7V brownout +atmega328_pro8_isp: EFUSE ?= DE +atmega328_pro8_isp: isp + +# 1MHz clocked platforms +# +# These are capable of 9600 baud +# + +luminet: TARGET = luminet +luminet: MCU_TARGET = attiny84 +luminet: CFLAGS += $(COMMON_OPTIONS) '-DSOFT_UART' '-DBAUD_RATE=9600' +luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION' +luminet: AVR_FREQ ?= 1000000L +luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe +luminet: $(PROGRAM)_luminet.hex +luminet: $(PROGRAM)_luminet.lst + +luminet_isp: luminet +luminet_isp: TARGET = luminet +luminet_isp: MCU_TARGET = attiny84 +# Brownout disabled +luminet_isp: HFUSE ?= DF +# 1MHz internal oscillator, slowly rising power +luminet_isp: LFUSE ?= 62 +# Self-programming enable +luminet_isp: EFUSE ?= FE +luminet_isp: isp + + +#--------------------------------------------------------------------------- +# +# Generic build instructions +# + +FORCE: + +baudcheck: FORCE + - @$(CC) $(CFLAGS) -E baudcheck.c -o baudcheck.tmp.sh + - @sh baudcheck.tmp.sh + +isp: $(TARGET) + $(MAKE) -f Makefile.isp isp TARGET=$(TARGET) + +isp-stk500: $(PROGRAM)_$(TARGET).hex + $(STK500-1) + $(STK500-2) + +%.elf: $(OBJ) baudcheck $(dummy) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) + $(SIZE) $@ + +clean: + rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.tmp.sh + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@ + +%.srec: %.elf + $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@ diff --git a/Optiboot.c b/Optiboot.c new file mode 100644 index 0000000..a63f9ae --- /dev/null +++ b/Optiboot.c @@ -0,0 +1,1069 @@ +////////////////////////////////////////////////////////////////////////// +// +// DualOptiboot +// Optiboot based custom bootloader for Moteino +// Enables wireless programming of Moteino wireless arduino clone +// Copyright Felix Rusu (2013), felix@lowpowerlab.com +// http://lowpowerlab.com/Moteino +// +////////////////////////////////////////////////////////////////////////// +// +// 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., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt +// +// Please maintain this license information along with authorship +// and copyright notices in any redistribution of this code +// +////////////////////////////////////////////////////////////////////////// +// +// This Optiboot version is modified to add the capability of reflashing +// from an external SPI flash memory chip. As configured this will work +// with Moteino (www.lowpowerlab.com/Moteino) provided a SPI flash chip +// is present on the dedicated onboard footprint. +// Summary of how this Optiboot version works: +// - it looks for an external flash chip +// - if one is found (SPI returns valid data) it will further look +// for a new sketch flash image signature and size +// starting at address 0: FLXIMG:NN:XXXXXXXXXXX +// where: - 'FLXIMG' is fixed signature indicating FLASH chip +// contains a valid new flash image to be burned +// - 'NN' are 2 size bytes (uint_16) indicating how long the +// new flash image is (how many bytes to read), max 65536Bytes +// - 'XXXXXX' are the de-hexified bytes of the flash +// pages to be burned +// - ':' colons have fixed positions (delimiters) +// - if no valid signature/size are found, it will skip and +// function as it normally would (listen to STK500 protocol on serial port) +// +// The added code will result in a compiled size of just under 1kb +// (Originally Optiboot takes just under 0.5kb) +// - Examples at: http://lowpowerlab.com/blog/category/moteino/wireless-programming/ +// - Tested on atmega328P and atmega644/1284P +// - Limited to 31K sketches for atmega328p and 64K sketches for atmega1284P. +////////////////////////////////////////////////////////////////////////// +/**********************************************************/ +/* Optiboot bootloader for Arduino */ +/* */ +/* http://optiboot.googlecode.com */ +/* */ +/* Arduino-maintained version : See README.TXT */ +/* http://code.google.com/p/arduino/ */ +/* It is the intent that changes not relevant to the */ +/* Arduino production envionment get moved from the */ +/* optiboot project to the arduino project in "lumps." */ +/* */ +/* Heavily optimised bootloader that is faster and */ +/* smaller than the Arduino standard bootloader */ +/* */ +/* Enhancements: */ +/* Fits in 512 bytes, saving 1.5K of code space */ +/* Background page erasing speeds up programming */ +/* Higher baud rate speeds up programming */ +/* Written almost entirely in C */ +/* Customisable timeout with accurate timeconstant */ +/* Optional virtual UART. No hardware UART required. */ +/* Optional virtual boot partition for devices without. */ +/* */ +/* What you lose: */ +/* Implements a skeleton STK500 protocol which is */ +/* missing several features including EEPROM */ +/* programming and non-page-aligned writes */ +/* High baud rate breaks compatibility with standard */ +/* Arduino flash settings */ +/* */ +/* Fully supported: */ +/* ATmega168 based devices (Diecimila etc) */ +/* ATmega328P based devices (Duemilanove etc) */ +/* */ +/* Beta test (believed working.) */ +/* ATmega8 based devices (Arduino legacy) */ +/* ATmega328 non-picopower devices */ +/* ATmega644P based devices (Sanguino) */ +/* ATmega1284P based devices */ +/* ATmega1280 based devices (Arduino Mega) */ +/* */ +/* Alpha test */ +/* ATmega32 */ +/* */ +/* Work in progress: */ +/* ATtiny84 based devices (Luminet) */ +/* */ +/* Does not support: */ +/* USB based devices (eg. Teensy, Leonardo) */ +/* */ +/* Assumptions: */ +/* The code makes several assumptions that reduce the */ +/* code size. They are all true after a hardware reset, */ +/* but may not be true if the bootloader is called by */ +/* other means or on other hardware. */ +/* No interrupts can occur */ +/* UART and Timer 1 are set to their reset state */ +/* SP points to RAMEND */ +/* */ +/* Code builds on code, libraries and optimisations from: */ +/* stk500boot.c by Jason P. Kyle */ +/* Arduino bootloader http://arduino.cc */ +/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */ +/* avr-libc project http://nongnu.org/avr-libc */ +/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */ +/* AVR305 Atmel Application Note */ +/* */ +/* 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., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* Licence can be viewed at */ +/* http://www.fsf.org/licenses/gpl.txt */ +/* */ +/**********************************************************/ + + +/**********************************************************/ +/* */ +/* Optional defines: */ +/* */ +/**********************************************************/ +/* */ +/* BIG_BOOT: */ +/* Build a 1k bootloader, not 512 bytes. This turns on */ +/* extra functionality. */ +/* */ +/* BAUD_RATE: */ +/* Set bootloader baud rate. */ +/* */ +/* LUDICROUS_SPEED: */ +/* 230400 baud :-) */ +/* */ +/* SOFT_UART: */ +/* Use AVR305 soft-UART instead of hardware UART. */ +/* */ +/* LED_START_FLASHES: */ +/* Number of LED flashes on bootup. */ +/* */ +/* LED_DATA_FLASH: */ +/* Flash LED when transferring data. For boards without */ +/* TX or RX LEDs, or for people who like blinky lights. */ +/* */ +/* SUPPORT_EEPROM: */ +/* Support reading and writing from EEPROM. This is not */ +/* used by Arduino, so off by default. */ +/* */ +/* TIMEOUT_MS: */ +/* Bootloader timeout period, in milliseconds. */ +/* 500,1000,2000,4000,8000 supported. */ +/* */ +/* UART: */ +/* UART number (0..n) for devices with more than */ +/* one hardware uart (644P, 1284P, etc) */ +/* */ +/**********************************************************/ + +/**********************************************************/ +/* Version Numbers! */ +/* */ +/* Arduino Optiboot now includes this Version number in */ +/* the source and object code. */ +/* */ +/* Version 3 was released as zip from the optiboot */ +/* repository and was distributed with Arduino 0022. */ +/* Version 4 starts with the arduino repository commit */ +/* that brought the arduino repository up-to-date with */ +/* the optiboot source tree changes since v3. */ +/* Version 5 was created at the time of the new Makefile */ +/* structure (Mar, 2013), even though no binaries changed*/ +/* It would be good if versions implemented outside the */ +/* official repository used an out-of-seqeunce version */ +/* number (like 104.6 if based on based on 4.5) to */ +/* prevent collisions. */ +/* */ +/**********************************************************/ + +/**********************************************************/ +/* Edit History: */ +/* */ +/* Mar 2013 */ +/* 5.0 WestfW: Major Makefile restructuring. */ +/* See Makefile and pin_defs.h */ +/* (no binary changes) */ +/* */ +/* 4.6 WestfW/Pito: Add ATmega32 support */ +/* 4.6 WestfW/radoni: Don't set LED_PIN as an output if */ +/* not used. (LED_START_FLASHES = 0) */ +/* Jan 2013 */ +/* 4.6 WestfW/dkinzer: use autoincrement lpm for read */ +/* 4.6 WestfW/dkinzer: pass reset cause to app in R2 */ +/* Mar 2012 */ +/* 4.5 WestfW: add infrastructure for non-zero UARTS. */ +/* 4.5 WestfW: fix SIGNATURE_2 for m644 (bad in avr-libc) */ +/* Jan 2012: */ +/* 4.5 WestfW: fix NRWW value for m1284. */ +/* 4.4 WestfW: use attribute OS_main instead of naked for */ +/* main(). This allows optimizations that we */ +/* count on, which are prohibited in naked */ +/* functions due to PR42240. (keeps us less */ +/* than 512 bytes when compiler is gcc4.5 */ +/* (code from 4.3.2 remains the same.) */ +/* 4.4 WestfW and Maniacbug: Add m1284 support. This */ +/* does not change the 328 binary, so the */ +/* version number didn't change either. (?) */ +/* June 2011: */ +/* 4.4 WestfW: remove automatic soft_uart detect (didn't */ +/* know what it was doing or why.) Added a */ +/* check of the calculated BRG value instead. */ +/* Version stays 4.4; existing binaries are */ +/* not changed. */ +/* 4.4 WestfW: add initialization of address to keep */ +/* the compiler happy. Change SC'ed targets. */ +/* Return the SW version via READ PARAM */ +/* 4.3 WestfW: catch framing errors in getch(), so that */ +/* AVRISP works without HW kludges. */ +/* http://code.google.com/p/arduino/issues/detail?id=368n*/ +/* 4.2 WestfW: reduce code size, fix timeouts, change */ +/* verifySpace to use WDT instead of appstart */ +/* 4.1 WestfW: put version number in binary. */ +/**********************************************************/ + +#define LED_DATA_FLASH 1 +#define OPTIBOOT_MAJVER 5 +#define OPTIBOOT_MINVER 0 + +#define MAKESTR(a) #a +#define MAKEVER(a, b) MAKESTR(a*256+b) + +asm(" .section .version\n" + "optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n" + " .section .text\n"); + +#include +#include +#include + +// uses sts instructions, but this version uses out instructions +// This saves cycles and program memory. +#include "boot.h" + + +// We don't use as those routines have interrupt overhead we don't need. + +#include "pin_defs.h" +#include "stk500.h" + +#ifndef LED_START_FLASHES +#define LED_START_FLASHES 1 +#endif + +#ifdef LUDICROUS_SPEED +#define BAUD_RATE 230400L +#endif + +/* set the UART baud rate defaults */ +#ifndef BAUD_RATE +#if F_CPU >= 8000000L +#define BAUD_RATE 115200L // Highest rate Avrdude win32 will support +#elsif F_CPU >= 1000000L +#define BAUD_RATE 9600L // 19200 also supported, but with significant error +#elsif F_CPU >= 128000L +#define BAUD_RATE 4800L // Good for 128kHz internal RC +#else +#define BAUD_RATE 1200L // Good even at 32768Hz +#endif +#endif + +#ifndef UART +#define UART 0 +#endif + +#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 ) +#define BAUD_ACTUAL (F_CPU/(8 * ((BAUD_SETTING)+1))) +#define BAUD_ERROR (( 100*(BAUD_RATE - BAUD_ACTUAL) ) / BAUD_RATE) + +#if BAUD_ERROR >= 5 +#error BAUD_RATE error greater than 5% +#elif BAUD_ERROR <= -5 +#error BAUD_RATE error greater than -5% +#elif BAUD_ERROR >= 2 +#warning BAUD_RATE error greater than 2% +#elif BAUD_ERROR <= -2 +#warning BAUD_RATE error greater than -2% +#endif + +#if 0 +/* Switch in soft UART for hard baud rates */ +/* + * I don't understand what this was supposed to accomplish, where the + * constant "280" came from, or why automatically (and perhaps unexpectedly) + * switching to a soft uart is a good thing, so I'm undoing this in favor + * of a range check using the same calc used to config the BRG... + */ +#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz +#ifndef SOFT_UART +#define SOFT_UART +#endif +#endif +#else // 0 +#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250 +#error Unachievable baud rate (too slow) BAUD_RATE +#endif // baud rate slow check +#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3 +#error Unachievable baud rate (too fast) BAUD_RATE +#endif // baud rate fastn check +#endif + +/* Watchdog settings */ +#define WATCHDOG_OFF (0) +#define WATCHDOG_16MS (_BV(WDE)) +#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE)) +#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE)) +#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE)) +#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE)) +#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE)) +#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE)) +#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE)) +#ifndef __AVR_ATmega8__ +#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE)) +#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE)) +#endif + +/* Function Prototypes */ +/* The main function is in init9, which removes the interrupt vector table */ +/* we don't need. It is also 'naked', which means the compiler does not */ +/* generate any entry or exit code itself. */ +int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))); +void putch(char); +uint8_t getch(void); +static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */ +void verifySpace(); +static inline void flash_led(uint8_t); +uint8_t getLen(); +static inline void watchdogReset(); +void watchdogConfig(uint8_t x); +#ifdef SOFT_UART +void uartDelay() __attribute__ ((naked)); +#endif +void appStart(uint8_t rstFlags) __attribute__ ((naked)); + +/* + * NRWW memory + * Addresses below NRWW (Non-Read-While-Write) can be programmed while + * continuing to run code from flash, slightly speeding up programming + * time. Beware that Atmel data sheets specify this as a WORD address, + * while optiboot will be comparing against a 16-bit byte address. This + * means that on a part with 128kB of memory, the upper part of the lower + * 64k will get NRWW processing as well, even though it doesn't need it. + * That's OK. In fact, you can disable the overlapping processing for + * a part entirely by setting NRWWSTART to zero. This reduces code + * space a bit, at the expense of being slightly slower, overall. + * + * RAMSTART should be self-explanatory. It's bigger on parts with a + * lot of peripheral registers. + */ +#if defined(__AVR_ATmega168__) +#define RAMSTART (0x100) +#define NRWWSTART (0x3800) +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32__) +#define RAMSTART (0x100) +#define NRWWSTART (0x7000) +#elif defined (__AVR_ATmega644P__) +#define RAMSTART (0x100) +#define NRWWSTART (0xE000) +// correct for a bug in avr-libc +#undef SIGNATURE_2 +#define SIGNATURE_2 0x0A +#elif defined (__AVR_ATmega1284P__) +#define RAMSTART (0x100) +#define NRWWSTART (0xE000) +#elif defined(__AVR_ATtiny84__) +#define RAMSTART (0x100) +#define NRWWSTART (0x0000) +#elif defined(__AVR_ATmega1280__) +#define RAMSTART (0x200) +#define NRWWSTART (0xE000) +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) +#define RAMSTART (0x100) +#define NRWWSTART (0x1800) +#endif + +/* C zero initialises all global variables. However, that requires */ +/* These definitions are NOT zero initialised, but that doesn't matter */ +/* This allows us to drop the zero init code, saving us memory */ +#define buff ((uint8_t*)(RAMSTART)) +#ifdef VIRTUAL_BOOT_PARTITION +#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4)) +#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6)) +#endif + +/* + * Handle devices with up to 4 uarts (eg m1280.) Rather inelegantly. + * Note that mega8/m32 still needs special handling, because ubrr is handled + * differently. + */ +#if UART == 0 +# define UART_SRA UCSR0A +# define UART_SRB UCSR0B +# define UART_SRC UCSR0C +# define UART_SRL UBRR0L +# define UART_UDR UDR0 +#elif UART == 1 +#if !defined(UDR1) +#error UART == 1, but no UART1 on device +#endif +# define UART_SRA UCSR1A +# define UART_SRB UCSR1B +# define UART_SRC UCSR1C +# define UART_SRL UBRR1L +# define UART_UDR UDR1 +#elif UART == 2 +#if !defined(UDR2) +#error UART == 2, but no UART2 on device +#endif +# define UART_SRA UCSR2A +# define UART_SRB UCSR2B +# define UART_SRC UCSR2C +# define UART_SRL UBRR2L +# define UART_UDR UDR2 +#elif UART == 3 +#if !defined(UDR1) +#error UART == 3, but no UART3 on device +#endif +# define UART_SRA UCSR3A +# define UART_SRB UCSR3B +# define UART_SRC UCSR3C +# define UART_SRL UBRR3L +# define UART_UDR UDR3 +#endif + +/******************* SPI FLASH Code **********************************/ +// This code will handle the reading/erasing the external SPI FLASH memory +// assumed to have the SPI_CS on D8 on Moteino (Atmega328P) +#define SPI_MODE0 0x00 +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR +#define SPI_CLOCK_DIV2 0x04 + +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) + #define FLASHSS_DDR DDRB + #define FLASHSS_PORT PORTB + #define FLASHSS PINB0 + #define SS PINB2 +#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) + #define FLASHSS_DDR DDRC + #define FLASHSS_PORT PORTC + #define FLASHSS PINC7 + #define SS PINB4 +#endif + +#define FLASH_SELECT { FLASHSS_PORT &= ~(_BV(FLASHSS)); } +#define FLASH_UNSELECT { FLASHSS_PORT |= _BV(FLASHSS); } + +#define SPIFLASH_STATUSWRITE 0x01 // write status register +#define SPIFLASH_STATUSREAD 0x05 // read status register +#define SPIFLASH_WRITEENABLE 0x06 // write enable +#define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) +#define SPIFLASH_BLOCKERASE_32K 0x52 // erase one 32K block of flash memory +#define SPIFLASH_BLOCKERASE_64K 0xD8 // erase one 32K block of flash memory +#define SPIFLASH_JEDECID 0x9F // read JEDEC ID +//#define DEBUG_ON // uncomment to enable Serial debugging + // (will output different characters depending on which path the bootloader takes) + +uint8_t SPI_transfer(uint8_t _data) { + SPDR = _data; + while (!(SPSR & _BV(SPIF))); + return SPDR; +} + +uint8_t FLASH_busy() +{ + FLASH_SELECT; + SPI_transfer(SPIFLASH_STATUSREAD); + uint8_t status = SPI_transfer(0); + FLASH_UNSELECT; + return status & 1; +} + +void FLASH_command(uint8_t cmd, uint8_t isWrite){ + if (isWrite) + { + FLASH_command(SPIFLASH_WRITEENABLE, 0); // Write Enable + FLASH_UNSELECT; + } + while(FLASH_busy()); //wait for chip to become available + FLASH_SELECT; + SPI_transfer(cmd); +} + +uint8_t FLASH_readByte(uint32_t addr) { + FLASH_command(SPIFLASH_ARRAYREADLOWFREQ, 0); + SPI_transfer(addr >> 16); + SPI_transfer(addr >> 8); + SPI_transfer(addr); + //SPI.transfer(0); //"dont care", needed with SPIFLASH_ARRAYREAD command only + uint8_t result = SPI_transfer(0); + FLASH_UNSELECT; + return result; +} + +void CheckFlashImage() { +#ifdef DEBUG_ON + putch('F'); +#endif + watchdogConfig(WATCHDOG_OFF); + + //SPI INIT +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) + DDRB |= _BV(FLASHSS) | _BV(SS) | _BV(PB3) | _BV(PB5); //OUTPUTS for FLASH_SS and SS, MOSI, SCK + FLASH_UNSELECT; //unselect FLASH chip + PORTB |= _BV(SS); //set SS HIGH +#elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) + DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS + DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK + FLASH_UNSELECT; //unselect FLASH chip + PORTB |= _BV(SS); //set SS HIGH +#endif + + //SPCR &= ~(_BV(DORD)); //MSB first + //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0 + //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2 + //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK); + + // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT. + SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode + + //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value + FLASH_SELECT; + SPI_transfer(SPIFLASH_JEDECID); + uint8_t deviceId = SPI_transfer(0); + FLASH_UNSELECT; + if (deviceId==0 || deviceId==0xFF) return; + + //global unprotect + FLASH_command(SPIFLASH_STATUSWRITE, 1); + SPI_transfer(0); + FLASH_UNSELECT; + + //check if any flash image exists on external FLASH chip + if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':') + { +#ifdef DEBUG_ON + putch('L'); +#endif + + uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8); + if (imagesize%2!=0) return; //basic check that we got even # of bytes + + uint16_t b, i, nextAddress=0; + + LED_PIN |= _BV(LED); + for (i=0; i 0 + // Set up Timer 1 for timeout counter + TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 +#endif +#ifndef SOFT_UART +#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) + UCSRA = _BV(U2X); //Double speed mode USART + UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx + UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 + UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); +#else + UART_SRA = _BV(U2X0); //Double speed mode USART0 + UART_SRB = _BV(RXEN0) | _BV(TXEN0); + UART_SRC = _BV(UCSZ00) | _BV(UCSZ01); + UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); +#endif +#endif + + // Set up watchdog to trigger after 500ms + watchdogConfig(WATCHDOG_1S); + +#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) + /* Set LED pin as output */ + LED_DDR |= _BV(LED); +#endif + +#ifdef SOFT_UART + /* Set TX pin as output */ + UART_DDR |= _BV(UART_TX_BIT); +#endif + +#if LED_START_FLASHES > 0 + /* Flash onboard LED to signal entering of bootloader */ + flash_led(LED_START_FLASHES * 2); +#endif + + /* Forever loop */ + for (;;) { + /* get character from UART */ + ch = getch(); + + if(ch == STK_GET_PARAMETER) { + unsigned char which = getch(); + verifySpace(); + if (which == 0x82) { + /* + * Send optiboot version as "minor SW version" + */ + putch(OPTIBOOT_MINVER); + } else if (which == 0x81) { + putch(OPTIBOOT_MAJVER); + } else { + /* + * GET PARAMETER returns a generic 0x03 reply for + * other parameters - enough to keep Avrdude happy + */ + putch(0x03); + } + } + else if(ch == STK_SET_DEVICE) { + // SET DEVICE is ignored + getNch(20); + } + else if(ch == STK_SET_DEVICE_EXT) { + // SET DEVICE EXT is ignored + getNch(5); + } + else if(ch == STK_LOAD_ADDRESS) { + // LOAD ADDRESS + uint16_t newAddress; + newAddress = getch(); + newAddress = (newAddress & 0xff) | (getch() << 8); +#ifdef RAMPZ + // Transfer top bit to RAMPZ + RAMPZ = (newAddress & 0x8000) ? 1 : 0; +#endif + newAddress += newAddress; // Convert from word address to byte address + address = newAddress; + verifySpace(); + } + else if(ch == STK_UNIVERSAL) { + // UNIVERSAL command is ignored + getNch(4); + putch(0x00); + } + /* Write memory, length is big endian and is in bytes */ + else if(ch == STK_PROG_PAGE) { + // PROGRAM PAGE - we support flash programming only, not EEPROM + uint8_t *bufPtr; + uint16_t addrPtr; + + getch(); /* getlen() */ + length = getch(); + getch(); + + // If we are in RWW section, immediately start page erase + if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); + + // While that is going on, read in page contents + bufPtr = buff; + do *bufPtr++ = getch(); + while (--length); + + // If we are in NRWW section, page erase has to be delayed until now. + // Todo: Take RAMPZ into account (not doing so just means that we will + // treat the top of both "pages" of flash as NRWW, for a slight speed + // decrease, so fixing this is not urgent.) + if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); + + // Read command terminator, start reply + verifySpace(); + + // If only a partial page is to be programmed, the erase might not be complete. + // So check that here + boot_spm_busy_wait(); + +#ifdef VIRTUAL_BOOT_PARTITION + if ((uint16_t)(void*)address == 0) { + // This is the reset vector page. We need to live-patch the code so the + // bootloader runs. + // + // Move RESET vector to WDT vector + uint16_t vect = buff[0] | (buff[1]<<8); + rstVect = vect; + wdtVect = buff[8] | (buff[9]<<8); + vect -= 4; // Instruction is a relative jump (rjmp), so recalculate. + buff[8] = vect & 0xff; + buff[9] = vect >> 8; + + // Add jump to bootloader at RESET vector + buff[0] = 0x7f; + buff[1] = 0xce; // rjmp 0x1d00 instruction + } +#endif + + // Copy buffer into programming buffer + bufPtr = buff; + addrPtr = (uint16_t)(void*)address; + ch = SPM_PAGESIZE / 2; + do { + uint16_t a; + a = *bufPtr++; + a |= (*bufPtr++) << 8; + __boot_page_fill_short((uint16_t)(void*)addrPtr,a); + addrPtr += 2; + } while (--ch); + + // Write from programming buffer + __boot_page_write_short((uint16_t)(void*)address); + boot_spm_busy_wait(); + +#if defined(RWWSRE) + // Reenable read access to flash + boot_rww_enable(); +#endif + + } + /* Read memory block mode, length is big endian. */ + else if(ch == STK_READ_PAGE) { + // READ PAGE - we only read flash + getch(); /* getlen() */ + length = getch(); + getch(); + + verifySpace(); + do { +#ifdef VIRTUAL_BOOT_PARTITION + // Undo vector patch in bottom page so verify passes + if (address == 0) ch=rstVect & 0xff; + else if (address == 1) ch=rstVect >> 8; + else if (address == 8) ch=wdtVect & 0xff; + else if (address == 9) ch=wdtVect >> 8; + else ch = pgm_read_byte_near(address); + address++; +#elif defined(RAMPZ) + // Since RAMPZ should already be set, we need to use EPLM directly. + // Also, we can use the autoincrement version of lpm to update "address" + // do putch(pgm_read_byte_near(address++)); + // while (--length); + // read a Flash and increment the address (may increment RAMPZ) + __asm__ ("elpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address)); +#else + // read a Flash byte and increment the address + __asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address)); +#endif + putch(ch); + } while (--length); + } + + /* Get device signature bytes */ + else if(ch == STK_READ_SIGN) { + // READ SIGN - return what Avrdude wants to hear + verifySpace(); + putch(SIGNATURE_0); + putch(SIGNATURE_1); + putch(SIGNATURE_2); + } + else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */ + // Adaboot no-wait mod + watchdogConfig(WATCHDOG_16MS); + verifySpace(); + } + else { + // This covers the response to commands like STK_ENTER_PROGMODE + verifySpace(); + } + putch(STK_OK); + } +} + +void putch(char ch) { +#ifndef SOFT_UART + while (!(UART_SRA & _BV(UDRE0))); + UART_UDR = ch; +#else + __asm__ __volatile__ ( + " com %[ch]\n" // ones complement, carry set + " sec\n" + "1: brcc 2f\n" + " cbi %[uartPort],%[uartBit]\n" + " rjmp 3f\n" + "2: sbi %[uartPort],%[uartBit]\n" + " nop\n" + "3: rcall uartDelay\n" + " rcall uartDelay\n" + " lsr %[ch]\n" + " dec %[bitcnt]\n" + " brne 1b\n" + : + : + [bitcnt] "d" (10), + [ch] "r" (ch), + [uartPort] "I" (_SFR_IO_ADDR(UART_PORT)), + [uartBit] "I" (UART_TX_BIT) + : + "r25" + ); +#endif +} + +uint8_t getch(void) { + uint8_t ch; + +#ifdef LED_DATA_FLASH +#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) + LED_PORT ^= _BV(LED); +#else + LED_PIN |= _BV(LED); +#endif +#endif + +#ifdef SOFT_UART + __asm__ __volatile__ ( + "1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge + " rjmp 1b\n" + " rcall uartDelay\n" // Get to middle of start bit + "2: rcall uartDelay\n" // Wait 1 bit period + " rcall uartDelay\n" // Wait 1 bit period + " clc\n" + " sbic %[uartPin],%[uartBit]\n" + " sec\n" + " dec %[bitCnt]\n" + " breq 3f\n" + " ror %[ch]\n" + " rjmp 2b\n" + "3:\n" + : + [ch] "=r" (ch) + : + [bitCnt] "d" (9), + [uartPin] "I" (_SFR_IO_ADDR(UART_PIN)), + [uartBit] "I" (UART_RX_BIT) + : + "r25" +); +#else + while(!(UART_SRA & _BV(RXC0))) + ; + if (!(UART_SRA & _BV(FE0))) { + /* + * A Framing Error indicates (probably) that something is talking + * to us at the wrong bit rate. Assume that this is because it + * expects to be talking to the application, and DON'T reset the + * watchdog. This should cause the bootloader to abort and run + * the application "soon", if it keeps happening. (Note that we + * don't care that an invalid char is returned...) + */ + watchdogReset(); + } + + ch = UART_UDR; +#endif + +#ifdef LED_DATA_FLASH +#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) + LED_PORT ^= _BV(LED); +#else + LED_PIN |= _BV(LED); +#endif +#endif + + return ch; +} + +#ifdef SOFT_UART +// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6) +// Adding 3 to numerator simulates nearest rounding for more accurate baud rates +#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6) +#if UART_B_VALUE > 255 +#error Baud rate too slow for soft UART +#endif + +void uartDelay() { + __asm__ __volatile__ ( + "ldi r25,%[count]\n" + "1:dec r25\n" + "brne 1b\n" + "ret\n" + ::[count] "M" (UART_B_VALUE) + ); +} +#endif + +void getNch(uint8_t count) { + do getch(); while (--count); + verifySpace(); +} + +void verifySpace() { + if (getch() != CRC_EOP) { + watchdogConfig(WATCHDOG_16MS); // shorten WD timeout + while (1) // and busy-loop so that WD causes + ; // a reset and app start. + } + putch(STK_INSYNC); +} + +#if LED_START_FLASHES > 0 +void flash_led(uint8_t count) { + do { + TCNT1 = -(F_CPU/(1024*16)); + TIFR1 = _BV(TOV1); + while(!(TIFR1 & _BV(TOV1))); +#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) + LED_PORT ^= _BV(LED); +#else + LED_PIN |= _BV(LED); +#endif + watchdogReset(); + } while (--count); +} +#endif + +// Watchdog functions. These are only safe with interrupts turned off. +void watchdogReset() { + __asm__ __volatile__ ( + "wdr\n" + ); +} + +void watchdogConfig(uint8_t x) { + WDTCSR = _BV(WDCE) | _BV(WDE); + WDTCSR = x; +} + +void appStart(uint8_t rstFlags) { + // save the reset flags in the designated register + // This can be saved in a main program by putting code in .init0 (which + // executes before normal c init code) to save R2 to a global variable. + __asm__ __volatile__ ("mov r2, %0\n" :: "r" (rstFlags)); + + watchdogConfig(WATCHDOG_OFF); + __asm__ __volatile__ ( +#ifdef VIRTUAL_BOOT_PARTITION + // Jump to WDT vector + "ldi r30,4\n" + "clr r31\n" +#else + // Jump to RST vector + "clr r30\n" + "clr r31\n" +#endif + "ijmp\n" + ); +} \ No newline at end of file diff --git a/README.md b/README.md index 61dae41..695306e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ # DualOptiboot -Zavaděč pro Arduino IDE a desky xPablo.cz \ No newline at end of file +Zavaděč pro Arduino IDE a desky xPablo.cz + +Based on: + +Custom Optiboot to add wireless programming capability to Moteino +Copyright Felix Rusu (2013-2014), felix@lowpowerlab.com +More at: http://lowpowerlab.com/Moteino + +This Optiboot version is modified to add the capability of reflashing +from an external SPI flash memory chip. As configured this will work +with Moteino (www.lowpowerlab.com/Moteino) provided a SPI flash chip +is present on the dedicated onboard footprint. +Summary of how this Optiboot version works: +- it looks for an external flash chip +- if one is found (SPI returns valid data) it will further look + for a new sketch flash image signature and size + starting at address 0: FLXIMG:9999:XXXXXXXXXXX + where: - 'FLXIMG' is fixed signature indicating FLASH chip + contains a valid new flash image to be burned + - '9999' are 4 size bytes indicating how long the + new flash image is (how many bytes to read) + - 'XXXXXX' are the de-hexified bytes of the flash + pages to be burned + - ':' colons have fixed positions (delimiters) +- if no valid signature/size are found, it will skip and + function as it normally would (listen to STK500 protocol on serial port) + +The added code will result in a compiled size of just under 1kb +(Originally Optiboot takes just under 0.5kb) + +------------------------------------------------------------------------------------------------------------- + +To compile copy the Optiboot.c and Makefile files where Optiboot is originally located, mine is at: +arduino-install-dir\hardware\arduino\bootloaders\optiboot\ +Backup the original files andbefore overwrite both files. +Then compile by running: +make atmega328 +make atmega1284p diff --git a/pin_defs.h b/pin_defs.h new file mode 100644 index 0000000..30b0a67 --- /dev/null +++ b/pin_defs.h @@ -0,0 +1,742 @@ +/*------------------------------------------------------------------------ */ +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) +/*------------------------------------------------------------------------ */ + +/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove + */ +#if !defined(LED) +#define LED B1 //D9 +#endif + +/* Ports for soft UART */ +#ifdef SOFT_UART +#define UART_PORT PORTD +#define UART_PIN PIND +#define UART_DDR DDRD +#define UART_TX_BIT 1 +#define UART_RX_BIT 0 +#endif +#endif + +#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega32__) + //Name conversion R.Wiersma + #define UCSR0A UCSRA + #define UDR0 UDR + #define UDRE0 UDRE + #define RXC0 RXC + #define FE0 FE + #define TIFR1 TIFR + #define WDTCSR WDTCR +#endif +#if defined(__AVR_ATmega32__) + #define WDCE WDTOE +#endif + +/* Luminet support */ +/*------------------------------------------------------------------------ */ +#if defined(__AVR_ATtiny84__) +/*------------------------------------------------------------------------ */ +/* Red LED is connected to pin PA4 */ +#if !defined(LED) +#define LED A4 +#endif + +/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */ +#ifdef SOFT_UART +#define UART_PORT PORTA +#define UART_PIN PINA +#define UART_DDR DDRA +#define UART_TX_BIT 2 +#define UART_RX_BIT 3 +#endif +#endif + +/*------------------------------------------------------------------------ */ +/* Sanguino support (and other 40pin DIP cpus) */ +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega32__) +/*------------------------------------------------------------------------ */ +/* Onboard LED is connected to pin PB0 on Sanguino */ +#if !defined(LED) +#define LED D7 //Moteino MEGA D15 +#endif + +/* Ports for soft UART */ +#ifdef SOFT_UART +#define UART_PORT PORTD +#define UART_PIN PIND +#define UART_DDR DDRD +#define UART_TX_BIT 1 +#define UART_RX_BIT 0 +#endif +#endif + +/*------------------------------------------------------------------------ */ +/* Mega support */ +#if defined(__AVR_ATmega1280__) +/*------------------------------------------------------------------------ */ +/* Onboard LED is connected to pin PB7 on Arduino Mega */ +#if !defined(LED) +#define LED B7 +#endif + +/* Ports for soft UART */ +#ifdef SOFT_UART +#define UART_PORT PORTE +#define UART_PIN PINE +#define UART_DDR DDRE +#define UART_TX_BIT 1 +#define UART_RX_BIT 0 +#endif +#endif + +/* + * ------------------------------------------------------------------------ + * A bunch of macros to enable the LED to be specifed as "B5" for bit 5 + * of port B, and similar. + */ + +#define A0 0x100 +#define A1 0x101 +#define A2 0x102 +#define A3 0x103 +#define A4 0x104 +#define A5 0x105 +#define A6 0x106 +#define A7 0x107 + +#define B0 0x200 +#define B1 0x201 +#define B2 0x202 +#define B3 0x203 +#define B4 0x204 +#define B5 0x205 +#define B6 0x206 +#define B7 0x207 + +#define C0 0x300 +#define C1 0x301 +#define C2 0x302 +#define C3 0x303 +#define C4 0x304 +#define C5 0x305 +#define C6 0x306 +#define C7 0x307 + +#define D0 0x400 +#define D1 0x401 +#define D2 0x402 +#define D3 0x403 +#define D4 0x404 +#define D5 0x405 +#define D6 0x406 +#define D7 0x407 + +#define E0 0x500 +#define E1 0x501 +#define E2 0x502 +#define E3 0x503 +#define E4 0x504 +#define E5 0x505 +#define E6 0x506 +#define E7 0x507 + +#define F0 0x600 +#define F1 0x601 +#define F2 0x602 +#define F3 0x603 +#define F4 0x604 +#define F5 0x605 +#define F6 0x606 +#define F7 0x607 + +#define G0 0x700 +#define G1 0x701 +#define G2 0x702 +#define G3 0x703 +#define G4 0x704 +#define G5 0x705 +#define G6 0x706 +#define G7 0x707 + +#define H0 0x800 +#define H1 0x801 +#define H2 0x802 +#define H3 0x803 +#define H4 0x804 +#define H5 0x805 +#define H6 0x806 +#define H7 0x807 + +#define J0 0xA00 +#define J1 0xA01 +#define J2 0xA02 +#define J3 0xA03 +#define J4 0xA04 +#define J5 0xA05 +#define J6 0xA06 +#define J7 0xA07 + +#define K0 0xB00 +#define K1 0xB01 +#define K2 0xB02 +#define K3 0xB03 +#define K4 0xB04 +#define K5 0xB05 +#define K6 0xB06 +#define K7 0xB07 + +#define L0 0xC00 +#define L1 0xC01 +#define L2 0xC02 +#define L3 0xC03 +#define L4 0xC04 +#define L5 0xC05 +#define L6 0xC06 +#define L7 0xC07 + + + +#if LED == B0 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB0 +#elif LED == B1 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB1 +#elif LED == B2 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB2 +#elif LED == B3 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB3 +#elif LED == B4 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB4 +#elif LED == B5 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB5 +#elif LED == B6 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB6 +#elif LED == B7 +#undef LED +#define LED_DDR DDRB +#define LED_PORT PORTB +#define LED_PIN PINB +#define LED PINB7 + +#elif LED == C0 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC0 +#elif LED == C1 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC1 +#elif LED == C2 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC2 +#elif LED == C3 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC3 +#elif LED == C4 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC4 +#elif LED == C5 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC5 +#elif LED == C6 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC6 +#elif LED == C7 +#undef LED +#define LED_DDR DDRC +#define LED_PORT PORTC +#define LED_PIN PINC +#define LED PINC7 + +#elif LED == D0 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND0 +#elif LED == D1 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND1 +#elif LED == D2 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND2 +#elif LED == D3 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND3 +#elif LED == D4 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND4 +#elif LED == D5 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND5 +#elif LED == D6 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND6 +#elif LED == D7 +#undef LED +#define LED_DDR DDRD +#define LED_PORT PORTD +#define LED_PIN PIND +#define LED PIND7 + +#elif LED == E0 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE0 +#elif LED == E1 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE1 +#elif LED == E2 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE2 +#elif LED == E3 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE3 +#elif LED == E4 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE4 +#elif LED == E5 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE5 +#elif LED == E6 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE6 +#elif LED == E7 +#undef LED +#define LED_DDR DDRE +#define LED_PORT PORTE +#define LED_PIN PINE +#define LED PINE7 + +#elif LED == F0 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF0 +#elif LED == F1 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF1 +#elif LED == F2 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF2 +#elif LED == F3 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF3 +#elif LED == F4 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF4 +#elif LED == F5 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF5 +#elif LED == F6 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF6 +#elif LED == F7 +#undef LED +#define LED_DDR DDRF +#define LED_PORT PORTF +#define LED_PIN PINF +#define LED PINF7 + +#elif LED == G0 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING0 +#elif LED == G1 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING1 +#elif LED == G2 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING2 +#elif LED == G3 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING3 +#elif LED == G4 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING4 +#elif LED == G5 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING5 +#elif LED == G6 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING6 +#elif LED == G7 +#undef LED +#define LED_DDR DDRG +#define LED_PORT PORTG +#define LED_PIN PING +#define LED PING7 + +#elif LED == H0 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH0 +#elif LED == H1 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH1 +#elif LED == H2 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH2 +#elif LED == H3 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH3 +#elif LED == H4 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH4 +#elif LED == H5 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH5 +#elif LED == H6 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH6 +#elif LED == H7 +#undef LED +#define LED_DDR DDRH +#define LED_PORT PORTH +#define LED_PIN PINH +#define LED PINH7 + +#elif LED == J0 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ0 +#elif LED == J1 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ1 +#elif LED == J2 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ2 +#elif LED == J3 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ3 +#elif LED == J4 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ4 +#elif LED == J5 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ5 +#elif LED == J6 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ6 +#elif LED == J7 +#undef LED +#define LED_DDR DDRJ +#define LED_PORT PORTJ +#define LED_PIN PINJ +#define LED PINJ7 + +#elif LED == K0 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK0 +#elif LED == K1 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK1 +#elif LED == K2 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK2 +#elif LED == K3 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK3 +#elif LED == K4 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK4 +#elif LED == K5 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK5 +#elif LED == K6 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK6 +#elif LED == K7 +#undef LED +#define LED_DDR DDRK +#define LED_PORT PORTK +#define LED_PIN PINK +#define LED PINK7 + +#elif LED == L0 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL0 +#elif LED == L1 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL1 +#elif LED == L2 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL2 +#elif LED == L3 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL3 +#elif LED == L4 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL4 +#elif LED == L5 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL5 +#elif LED == L6 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL6 +#elif LED == L7 +#undef LED +#define LED_DDR DDRL +#define LED_PORT PORTL +#define LED_PIN PINL +#define LED PINL7 + +#elif LED == A0 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA0 +#elif LED == A1 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA1 +#elif LED == A2 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA2 +#elif LED == A3 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA3 +#elif LED == A4 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA4 +#elif LED == A5 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA5 +#elif LED == A6 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA6 +#elif LED == A7 +#undef LED +#define LED_DDR DDRA +#define LED_PORT PORTA +#define LED_PIN PINA +#define LED PINA7 + +#else +#error ------------------------------------------- +#error Unrecognized LED name. Should be like "B5" +#error ------------------------------------------- +#endif