Explorar el Código

Add optiboot bootloader (modified)

k4be hace 4 años
padre
commit
5e6859131d

+ 737 - 0
optiboot/Makefile

@@ -0,0 +1,737 @@
+# 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
+# 201406xx: WestfW: More Makefile restructuring.
+#                   Split off Makefile.1284, Makefile.extras, Makefile.custom
+#                   So that in theory, the main Makefile contains only the
+#                   official platforms, and does not need to be modified to
+#                   add "less supported" chips and boards.
+# 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
+#
+#
+# * Copyright 2013-2015 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+
+HELPTEXT = "\n"
+#----------------------------------------------------------------------
+#
+# 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 = atmega644p
+BIGBOOT = 0
+BOOT_ON_POR = 1
+APP_ON_EXTR = 0
+TIMEOUT = 4
+UART = 1
+SINGLESPEED = 0
+BAUD_RATE = 230400
+LED_DATA_FLASH = 0
+AVR_FREQ = 7372800L
+LED = A6
+LED_START_ON = 1
+LED_START_FLASHES = 0
+LDSECTIONS  = -Wl,-Tlink_optiboot.ld -Wl,-section-start=.manualcall=0x7ffa
+all: atmega644p
+
+# 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)
+SH := bash
+
+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.
+# (except that in 1.5.x, there's an additional level of "up")
+TESTDIR := $(firstword $(wildcard ../../../tools/*))
+ifeq (,$(TESTDIR))
+# Arduino 1.5.x tool location compared to optiboot dir
+  TOOLROOT = ../../../../tools
+else
+# Arduino 1.0 (and earlier) tool location
+  TOOLROOT = ../../../tools
+endif
+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
+SH = sh
+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-split-wide-types -mrelax
+
+DEFS       = 
+
+CC         = $(GCCROOT)avr-gcc
+
+# Override is only needed by avr-lib build system.
+
+HELPTEXT += "Option AVR_FREQ=<n>          - Clock rate of AVR CPU\n"
+
+
+override CFLAGS        = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
+override LDFLAGS       = $(LDSECTIONS) -Wl,--relax -nostartfiles
+
+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 PRODUCTION
+ifneq ($(PRODUCTION),0)
+VERSION_CMD = -DPRODUCTION=1
+endif
+dummy = FORCE
+endif
+
+HELPTEXT += "Option CUSTOM_VERSION=nn     - set a customer version number\n"
+ifdef CUSTOM_VERSION
+ifneq ($(CUSTOM_VERSION), 0)
+VERSION_CMD = -DOPTIBOOT_CUSTOMVER=$(CUSTOM_VERSION)
+else
+VERSION_CMD = -DPRODUCTION=1
+endif
+dummy = FORCE
+endif
+
+HELPTEXT += "Option BAUD_RATE=nnnn        - set the bit rate for communications\n"
+ifdef BAUD_RATE
+BAUD_RATE_CMD = -DBAUD_RATE=$(BAUD_RATE)
+dummy = FORCE
+else
+BAUD_RATE_CMD = -DBAUD_RATE=115200
+endif
+
+HELPTEXT += "Option LED=B3                - set LED pin to particular port/bit\n"
+ifdef LED
+LED_CMD = -DLED=$(LED)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option LED_START_FLASHES=n   - set number of LED flashes when bootloader starts\n"
+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
+
+HELPTEXT += "Option LED_DATA_FLASH=1      - flash the LED each time data is received.\n"
+ifdef LED_DATA_FLASH
+ifneq ($(LED_DATA_FLASH), 0)
+LED_DATA_FLASH_CMD = -DLED_DATA_FLASH=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option LED_START_ON=1        - Turn the LED on at bootload start\n"
+ifdef LED_START_ON
+ifneq ($(LED_START_ON), 0)
+LED_START_ON_CMD = -DLED_START_ON=1
+endif
+dummy = FORCE
+endif
+
+HELPTEXT += "Option BIGBOOT=1             - enable extra features up to 1kbytes\n"
+# BIGBOOT: Include extra features, up to 1K.
+ifdef BIGBOOT
+ifneq ($(BIGBOOT), 0)
+BIGBOOT_CMD = -DBIGBOOT=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option SUPPORT_EEPROM=1      - Include code to read/write EEPROM\n"
+ifdef SUPPORT_EEPROM
+ifneq ($(SUPPORT_EEPROM), 0)
+SUPPORT_EEPROM_CMD = -DSUPPORT_EEPROM
+dummy = FORCE
+endif
+endif
+
+
+HELPTEXT += "Option SOFT_UART=1           - use a software (bit-banged) UART\n"
+ifdef SOFT_UART
+ifneq ($(SOFT_UART), 0)
+SOFT_UART_CMD = -DSOFT_UART=1
+dummy = FORCE
+endif
+endif
+HELPTEXT += "Option SOFTTX=B5             - pin for software UART xmit \n"
+ifdef SOFTTX
+SOFT_UART_CMD += -DSOFTTX=$(SOFTTX)
+dummy = FORCE
+endif
+HELPTEXT += "Option SOFTRX=B6             - pin for software UART receive\n"
+ifdef SOFTRX
+SOFT_UART_CMD += -DSOFTRX=$(SOFTRX)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option SINGLESPEED=1         - do not use U2X mode on UART\n"
+ifdef SINGLESPEED
+ifneq ($(SINGLESPEED), 0)
+SS_CMD = -DSINGLESPEED=1
+endif
+endif
+
+HELPTEXT += "Option RS485=B0              - Pin for optional rs485 tx enable\n"
+ifdef RS485
+RS485_CMD = -DRS485=$(RS485)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option NO_APP_SPM=1          - disallow application call of do_spm\n"
+ifdef NO_APP_SPM
+ifneq ($(NO_APP_SPM),0)
+APPSPM_CMD = -DAPP_NOSPM=1
+endif
+endif
+
+HELPTEXT += "Option OSCCAL_VALUE=nnn      - set set OSCCAL_VALUE in bootloader\n"
+ifdef OSCCAL_VALUE
+OSCCAL_VALUE_CMD = -DOSCCAL_VALUE=$(OSCCAL_VALUE)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option BOOT_ON_POR           - Run bootloader on power-on\n"
+ifdef NO_START_APP_ON_POR
+ifneq ($(NO_START_APP_ON_POR),0)
+POR_CMD = -DNO_START_APP_ON_POR=1
+dummy = FORCE
+endif
+endif
+
+ifdef BOOT_ON_POR
+ifneq ($(NO_START_APP_ON_POR),0)
+POR_CMD = -DNO_START_APP_ON_POR=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option APP_ON_EXTR           - Run App on External Reset\n"
+ifdef START_APP_ON_EXTR
+ifneq ($(START_APP_ON_EXTR),0)
+EXTR_CMD = -DSTART_APP_ON_EXTR=1
+dummy = FORCE
+endif
+endif
+ifdef APP_ON_EXTR
+ifneq ($(START_APP_ON_EXTR),0)
+EXTR_CMD = -DSTART_APP_ON_EXTR=1
+dummy = FORCE
+endif
+endif
+
+
+COMMON_OPTIONS = $(BAUD_RATE_CMD) $(LED_START_FLASHES_CMD) $(BIGBOOT_CMD)
+COMMON_OPTIONS += $(SOFT_UART_CMD) $(LED_DATA_FLASH_CMD) $(LED_CMD) $(SS_CMD)
+COMMON_OPTIONS += $(SUPPORT_EEPROM_CMD) $(LED_START_ON_CMD) $(APPSPM_CMD)
+COMMON_OPTIONS += $(OSCCAL_VALUE_CMD) $(VERSION_CMD) $(TIMEOUT_CMD)
+COMMON_OPTIONS += $(POR_CMD) $(EXTR_CMD) $(RS485_CMD)
+
+#UART is handled separately and only passed for devices with more than one.
+HELPTEXT += "Option UART=n                - use UARTn for communications\n"
+ifdef UART
+UART_CMD = -DUART=$(UART)
+endif
+ifdef UARTTX
+UART_CMD = -DUARTTX=$(UARTTX)
+endif
+
+HELPTEXT += "Option TIMEOUT=n             - set WDT to 1, 2, 4, or 8 seconds\n"
+ifdef TIMEOUT
+TIMEOUT_CMD = -DWDTTIME=$(TIMEOUT)
+dummy = FORCE
+endif
+
+
+.PRECIOUS: %.elf
+
+#---------------------------------------------------------------------------
+# "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.
+#---------------------------------------------------------------------------
+#
+
+HELPTEXT += "\n-------------\n\n"
+
+# Test platforms
+# Virtual boot block test
+HELPTEXT += "target virboot8      - ATmega8 with virtual boot partition\n"
+virboot8: TARGET = atmega8
+virboot8: MCU_TARGET = atmega8
+virboot8: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-Dsave_vect_num=EE_RDY_vect_num'
+virboot8: AVR_FREQ ?= 16000000L 
+virboot8: $(PROGRAM)_virboot8.hex
+ifndef PRODUCTION
+virboot8: $(PROGRAM)_virboot8.lst
+endif
+
+
+HELPTEXT += "target virboot328p   - ATmega328 with virtual boot partition\n"
+virboot328: TARGET = atmega328
+virboot328: MCU_TARGET = atmega328p
+virboot328: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION'
+virboot328: AVR_FREQ ?= 16000000L
+virboot328: $(PROGRAM)_virboot328.hex
+ifndef PRODUCTION
+virboot328: $(PROGRAM)_virboot328.lst
+endif
+
+virboot328_isp: virboot328
+virboot328_isp: TARGET = virboot328
+virboot328_isp: MCU_TARGET = atmega328p
+# no boot section, SPIEN
+virboot328_isp: HFUSE ?= DF
+# Low power xtal (16MHz) 16KCK/14CK+65ms
+virboot328_isp: LFUSE ?= FF
+# 2.7V brownout
+virboot328_isp: EFUSE ?= FD
+virboot328_isp: isp
+
+virboot8_isp: virboot8
+virboot8_isp: TARGET = virboot8
+virboot8_isp: MCU_TARGET = atmega8
+# SPIEN, CKOPT (for full swing xtal), boot section 1k
+#  Note that we need boot section to include our SPM instructions,
+#   even though we do not enable BOOTRST
+virboot8_isp: HFUSE ?= CB
+# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms
+virboot8_isp: LFUSE ?= BF
+virboot8_isp: isp
+
+
+
+# Diecimila, Duemilanove with m168, and NG use identical bootloaders
+# Call it "atmega168" for generality and clarity, keep "diecimila" for
+# backward compatibility of makefile
+
+# ATmega8
+#
+HELPTEXT += "target atmega8       - ATmega8, ATmega8A, ATmega8L\n"
+atmega8: TARGET = atmega8
+atmega8: MCU_TARGET = atmega8
+atmega8: CFLAGS += $(COMMON_OPTIONS)
+atmega8: AVR_FREQ ?= 16000000L 
+atmega8: $(PROGRAM)_atmega8.hex
+ifndef PRODUCTION
+atmega8: $(PROGRAM)_atmega8.lst
+endif
+
+atmega8_isp: atmega8
+atmega8_isp: TARGET = atmega8
+atmega8_isp: MCU_TARGET = atmega8
+ifndef BIGBOOT
+# SPIEN, CKOPT (for full swing xtal), Bootsize=512B
+atmega8_isp: HFUSE ?= CC
+else
+# SPIEN, CKOPT (for full swing xtal), Bootsize=1024B
+atmega8_isp: HFUSE ?= CA
+endif
+# 2.7V brownout, 16MHz Xtal, 16KCK/14CK+65ms
+atmega8_isp: LFUSE ?= BF
+atmega8_isp: isp
+
+HELPTEXT += "target atmega168*    - ATmega168/A, ATmega168P, ATMEGA1268PB\n"
+atmega168: TARGET = atmega168
+atmega168: MCU_TARGET = atmega168
+atmega168: CFLAGS += $(COMMON_OPTIONS)
+atmega168: AVR_FREQ ?= 16000000L
+atmega168: $(PROGRAM)_atmega168.hex
+ifndef PRODUCTION
+atmega168: $(PROGRAM)_atmega168.lst
+endif
+
+atmega168_isp: atmega168
+atmega168_isp: TARGET = atmega168
+# 2.7V brownout
+atmega168_isp: HFUSE ?= DD
+# Full swing (16MHz) 16KCK/14CK+65ms
+atmega168_isp: LFUSE ?= F7
+ifndef BIGBOOT
+# 512 byte boot
+atmega168_isp: EFUSE ?= FC
+else
+# 1024byte boot
+atmega168_isp: EFUSE ?= FA
+endif
+atmega168_isp: isp
+
+HELPTEXT += "target atmega328*    - ATmega328, ATmega328p, ATmega328pb\n"
+atmega328: TARGET = atmega328
+atmega328: MCU_TARGET = atmega328p
+atmega328: CFLAGS += $(COMMON_OPTIONS)
+atmega328: AVR_FREQ ?= 16000000L
+atmega328: $(PROGRAM)_atmega328.hex
+ifndef PRODUCTION
+atmega328: $(PROGRAM)_atmega328.lst
+endif
+
+atmega328_isp: atmega328
+atmega328_isp: TARGET = atmega328
+atmega328_isp: MCU_TARGET = atmega328p
+ifndef BIGBOOT
+# 512 byte boot, SPIEN
+atmega328_isp: HFUSE ?= DE
+else
+# 1k byte boot, SPIEN
+atmega328_isp: HFUSE ?= DC
+endif
+# Low power xtal (16MHz) 16KCK/14CK+65ms
+atmega328_isp: LFUSE ?= FF
+# 2.7V brownout
+atmega328_isp: EFUSE ?= FD
+atmega328_isp: isp
+
+#Atmega1280
+#HELPTEXT += "target atmega1280    - ATmega1280 (100pin, 128k)\n"
+atmega1280: MCU_TARGET = atmega1280
+atmega1280: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega1280: AVR_FREQ ?= 16000000L
+atmega1280: $(PROGRAM)_atmega1280.hex
+ifndef PRODUCTION
+atmega1280: $(PROGRAM)_atmega1280.lst
+endif
+
+
+
+#---------------------------------------------------------------------------
+# "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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+pro20_isp: pro20
+pro20_isp: TARGET = pro_20mhz
+# 4.3V brownout (for max speed!)
+pro20_isp: HFUSE ?= DC
+# Full swing xtal (20MHz) 258CK/14CK+4.1ms
+pro20_isp: LFUSE ?= F7
+# 512 byte boot
+pro20_isp: EFUSE ?= FC
+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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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 ?= F7
+# 512 byte boot
+pro16_isp: EFUSE ?= FC
+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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+diecimila_isp: diecimila
+diecimila_isp: TARGET = diecimila
+# 2.7V brownout
+diecimila_isp: HFUSE ?= DD
+# Low power xtal (16MHz) 16KCK/14CK+65ms
+diecimila_isp: LFUSE ?= F7
+# 512 byte boot
+diecimila_isp: EFUSE ?= FC
+diecimila_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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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 ?= FC
+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 ?= FC
+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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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 ?= FC
+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
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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 ?= FD
+atmega328_pro8_isp: isp
+
+#
+# Include additional platforms
+include Makefile.atmel
+include Makefile.extras
+include Makefile.1284
+include Makefile.custom
+include Makefile.2560
+include Makefile.tiny
+include Makefile.mcudude
+include Makefile.usbmcus
+
+BAUDCHECK=
+ifndef PRODUCTION
+ifndef SOFT_UART
+BAUDCHECK= baudcheck
+endif
+endif
+
+#---------------------------------------------------------------------------
+#
+# Generic build instructions
+#
+
+FORCE:
+
+baudcheck: FORCE
+	- @$(CC) --version
+	- @$(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) $@
+
+#windows "rm" is dumb and objects to wildcards that don't exist
+clean:
+	@touch  __temp_.o __temp_.elf __temp_.lst __temp_.map
+	@touch  __temp_.sym __temp_.lss __temp_.eep __temp_.srec
+	@touch __temp_.bin __temp_.hex __temp_.tmp.sh
+	rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.tmp.sh
+
+clean_asm:
+	rm -rf *.lst
+
+%.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 $< $@
+
+help:
+	@echo -e $(HELPTEXT)
+
+install: all
+	avrdude -c usbasp -p atmega644p -U lfuse:w:0xff:m -U hfuse:w:0x14:m -U efuse:w:0xfe:m -B100
+	avrdude -c usbasp -p atmega644p -U flash:w:optiboot_atmega644p.hex

+ 158 - 0
optiboot/Makefile.1284

@@ -0,0 +1,158 @@
+#
+# Makefile for 40-pin AVR chips, including ATmega644 and ATmega1284
+#
+# * Copyright 2013-2015 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+
+# Chip level targets
+#
+HELPTEXT += "target atmega644p    - ATmega644p\n"
+atmega644p: TARGET = atmega644p
+atmega644p: MCU_TARGET = atmega644p
+atmega644p: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT
+atmega644p: AVR_FREQ ?= 16000000L
+atmega644p: CFLAGS += $(UART_CMD)
+atmega644p: $(PROGRAM)_atmega644p.hex
+ifndef PRODUCTION
+atmega644p: $(PROGRAM)_atmega644p.lst
+endif
+
+HELPTEXT += "target atmega1284    - ATmega1284p (40 pin, 128k)\n"
+atmega1284: TARGET = atmega1284p
+atmega1284: MCU_TARGET = atmega1284p
+atmega1284: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT
+atmega1284: AVR_FREQ ?= 16000000L
+atmega1284: CFLAGS += $(UART_CMD)
+atmega1284: $(PROGRAM)_atmega1284p.hex
+ifndef PRODUCTION
+atmega1284: $(PROGRAM)_atmega1284p.lst
+endif
+
+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
+
+#
+# Board-level targets
+#
+
+# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
+#
+HELPTEXT += "target sanguino      - ATmega644p board\n"
+sanguino: TARGET = $@
+sanguino: CHIP = atmega644p
+sanguino:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B0
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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
+
+HELPTEXT += "target mighty1284    - ManiacBug Mighty1284 board\n"
+mighty1284: TARGET = $@
+mighty1284: CHIP = atmega1284p
+mighty1284:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B7
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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
+
+HELPTEXT += "target bobuino       - Crossroads 1284 board\n"
+bobuino: TARGET = $@
+bobuino: CHIP = atmega1284p
+bobuino:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B7
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+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
+
+#
+# Wicked Devices "Wildfire" boards (1284 with wireless!)
+#
+
+HELPTEXT += "target wildfirev2    - Wicked Devices board\n"
+wildfirev2: TARGET = $@
+wildfirev2: CHIP = atmega1284p
+wildfirev2:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B7 BAUD_RATE=1000000
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+wildfirev2_isp: wildfirev2
+wildfirev2_isp: TARGET = wildfirev2
+wildfirev2_isp: MCU_TARGET = atmega1284p
+# 1024 byte boot
+wildfirev2_isp: HFUSE ?= DE
+# Full swing xtal (16MHz) 16KCK/14CK+65ms
+wildfirev2_isp: LFUSE ?= F7
+# 2.7V brownout
+wildfirev2_isp: EFUSE ?= FD
+wildfirev2_isp: isp
+
+HELPTEXT += "target wildfirev3    - Wicked Devices board\n"
+wildfirev3: TARGET = $@
+wildfirev3: CHIP = atmega1284p
+wildfirev3:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B5
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+wildfirev3_isp: wildfirev3
+wildfirev3_isp: TARGET = wildfirev3
+wildfirev3_isp: MCU_TARGET = atmega1284p
+# 1024 byte boot
+wildfirev3_isp: HFUSE ?= DE
+# Full swing xtal (16MHz) 16KCK/14CK+65ms
+wildfirev3_isp: LFUSE ?= F7
+# 2.7V brownout
+wildfirev3_isp: EFUSE ?= FD
+wildfirev3_isp: isp

+ 59 - 0
optiboot/Makefile.2560

@@ -0,0 +1,59 @@
+#
+# Makefile for 2560 AVR chips
+#
+# * Copyright 2013-2015 by Bill Westfield, Marek Wodzinski.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+
+# Chip level targets
+#
+HELPTEXT += "target atmega2560    - ATmega2560p (100pin, 256k)\n"
+atmega2560: TARGET = atmega2560
+atmega2560: MCU_TARGET = atmega2560
+atmega2560: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT
+atmega2560: AVR_FREQ ?= 16000000L
+atmega2560: CFLAGS += $(UART_CMD)
+atmega2560: $(PROGRAM)_atmega2560.hex
+ifndef PRODUCTION
+atmega2560: $(PROGRAM)_atmega2560.lst
+endif
+
+
+atmega2560_isp: atmega2560
+atmega2560_isp: TARGET = atmega2560
+atmega2560_isp: MCU_TARGET = atmega2560
+# 1024 byte boot, JTAG disabled
+atmega2560_isp: HFUSE ?= DE
+# Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega2560_isp: LFUSE ?= F7
+# 2.7V brownout
+atmega2560_isp: EFUSE ?= FD
+atmega2560_isp: isp
+
+#
+# Board-level targets
+#
+
+# Arduino/Geniuno MEGA 256 has a minimum boot size of 1024 bytes, so enable extra functions
+#
+HELPTEXT += "target mega2560      - Arduino MEGA2560 board, 2560ADK\n"
+mega2560: TARGET = $@
+mega2560: CHIP = atmega2560
+mega2560:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+mega2560_isp: mega256
+mega2560_isp: TARGET = mega2560
+mega2560_isp: MCU_TARGET = atmega2560
+# 1024 byte boot, JTAG disabled
+mega2560_isp: HFUSE ?= DE
+# Full swing xtal (16MHz) 16KCK/14CK+65ms
+mega2560_isp: LFUSE ?= F7
+# 2.7V brownout
+mega2560_isp: EFUSE ?= FD
+mega2560_isp: isp
+

+ 43 - 0
optiboot/Makefile.atmel

@@ -0,0 +1,43 @@
+# 
+# Support for the Atmel Xplained mini eval boards that are mostly
+#   compatible with Arduino.  (168pb, 328p, and 328pb chips.)
+#
+# Currently these all masquerade as 168 or 328p, because the IDE
+#  does not yet have compiler support for the -pb variants.
+#
+# These boards have an mEDBG debug chip that:
+#   1) means that optiboot can only be programmed via Atmel Studio
+#   2) prevents optiboot from working at 115200bps.
+#   3) provides 16MHz (at 5V) via Xin on the chip.
+#  
+# 
+#
+HELPTEXT += "target xplained168pb - Atmel Xplained Mini 168pb Eval board\n"
+xplained168pb: TARGET = $@
+xplained168pb: CHIP = atmega168
+xplained168pb:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L BAUD_RATE=57600
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+HELPTEXT += "target xplained328pb - Atmel Xplained Mini 328pb Eval board\n"
+xplained328pb: TARGET = $@
+xplained328pb: CHIP = atmega328
+xplained328pb:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L BAUD_RATE=57600
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+
+HELPTEXT += "target xplained328p  - Atmel Xplained Mini 328p Eval board\n"
+xplained328p: TARGET = $@
+xplained328p: CHIP = atmega328
+xplained328p:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L BAUD_RATE=57600
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif

+ 18 - 0
optiboot/Makefile.custom

@@ -0,0 +1,18 @@
+#
+# Makefile for "custom" platforms.   Add your board here.
+#
+# * Copyright 2013-2015 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+
+
+HELPTEXT += "target wildfire      - Wicked Devices Wildfire v1 board\n"
+wildfire: TARGET = $@
+wildfire: CHIP = atmega1284p
+wildfire:
+	"$(MAKE)" $(CHIP) AVR_FREQ=16000000L LED=B5
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).lst
+endif
+

+ 129 - 0
optiboot/Makefile.extras

@@ -0,0 +1,129 @@
+#
+# Makefile for "other" implemented platforms.
+#
+# * Copyright 2013-2015 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+#
+
+#
+# Extra chips (maybe) supported by optiboot
+# Note that these are usually only minimally tested.
+#
+
+#
+# ATmega88
+#
+HELPTEXT += "target atmega88      - ATmega88 or ATmega88p (28pin, 8k)\n"
+atmega88: TARGET = atmega88
+atmega88: MCU_TARGET = atmega88
+atmega88: CFLAGS += $(COMMON_OPTIONS)
+atmega88: AVR_FREQ ?= 16000000L 
+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
+atmega88_isp: LFUSE ?= FF
+# 512 byte boot
+atmega88_isp: EFUSE ?= 04
+atmega88_isp: isp
+
+atmega88p_isp: atmega88
+atmega88p_isp: TARGET = atmega88
+atmega88p_isp: MCU_TARGET = atmega88p
+# 2.7V brownout
+atmega88p_isp: HFUSE ?= DD
+# Low power xtal (16MHz) 16KCK/14CK+65ms
+atmega88p_isp: LFUSE ?= FF
+# 512 byte boot
+atmega88p_isp: EFUSE ?= 04
+atmega88p_isp: isp
+
+#
+# ATmega168p [QFN32]
+#
+HELPTEXT += "target atmega168p    - ATmega168p\n"
+atmega168p: TARGET = atmega168p
+atmega168p: MCU_TARGET = atmega168p
+atmega168p: CFLAGS += $(COMMON_OPTIONS)
+atmega168p: AVR_FREQ ?= 16000000L 
+atmega168p: $(PROGRAM)_atmega168p_16MHz.hex
+atmega168p: $(PROGRAM)_atmega168p_16MHz.lst
+
+atmega168p_isp: atmega168p
+atmega168p_isp: TARGET = atmega168p
+# 2.7V brownout
+atmega168p_isp: HFUSE ?= DD
+# Low power xtal (16MHz) 16KCK/14CK+65ms
+atmega168p_isp: LFUSE ?= FF
+# 512 byte boot
+atmega168p_isp: EFUSE ?= 04
+atmega168p_isp: isp
+
+HELPTEXT += "target atmega16      - ATmega16 (40pin, 16k)\n"
+atmega16: TARGET = atmega16
+atmega16: MCU_TARGET = atmega16
+atmega16: CFLAGS += $(COMMON_OPTIONS)
+atmega16: AVR_FREQ ?= 16000000L 
+atmega16: $(PROGRAM)_atmega16.hex
+atmega16: $(PROGRAM)_atmega16.lst
+
+#
+# ATmega32
+#
+HELPTEXT += "target atmega32      - ATmega32 (40pin, 32k)\n"
+atmega32: TARGET = atmega32
+atmega32: MCU_TARGET = atmega32
+atmega32: CFLAGS += $(COMMON_OPTIONS)
+atmega32: AVR_FREQ ?= 11059200L
+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
+atmega32_isp: LFUSE ?= BF
+atmega32_isp: isp
+
+#Atmega128RFA1
+HELPTEXT += "target atmega128rfa1  - ATmega128RFA1 (100pin, 128k)\n"
+atmega128rfa1: MCU_TARGET = atmega128rfa1
+atmega128rfa1: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega128rfa1: AVR_FREQ ?= 16000000L
+atmega128rfa1: $(PROGRAM)_atmega128rfa1.hex
+ifndef PRODUCTION
+atmega128rfa1: $(PROGRAM)_atmega128rfa1.lst
+endif
+
+
+# 1MHz clocked platforms/boards
+#
+# These are capable of 9600 baud
+#
+
+luminet: TARGET = $@
+luminet: CHIP = attiny84
+luminet:
+	"$(MAKE)" $(CHIP) AVR_FREQ=1000000L LED_START_FLASHES=0 BAUD_RATE=9600
+	mv $(PROGRAM)_$(CHIP).hex $(PROGRAM)_$(TARGET).hex
+	mv $(PROGRAM)_$(CHIP).lst $(PROGRAM)_$(TARGET).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
+

+ 96 - 0
optiboot/Makefile.isp

@@ -0,0 +1,96 @@
+# Makefile.isp for Optiboot
+# Bill Westfield (WestfW@yahoo.com)  March, 2013
+# $Id$
+#
+# Instructions:
+#
+# This is a "daughter" Makefile that burns the bootloader using a ISP
+# device programmer.  It is designed to inherit assorted variables from
+# the parent optiboot "Makefile"...  Using a daughter makefile makes
+# certain variable manipulations more obvious.
+#
+# To burn bootloader .hex file, invoke the main Makefile using:
+# make diecimila_isp
+# make lilypad_isp
+# make ng_isp
+# etc...
+#
+#
+# Note: inherit paths/etc from parent Makefile.
+#
+#---------------------------------------------------------------------------
+# 
+# * Copyright 2013-2015 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+# 
+#---------------------------------------------------------------------------
+
+# enter the parameters for the avrdude isp tool  -b19200
+#
+
+# Inherit avrdude paths from top-level makefile
+AVRDUDE_ROOT ?= $(GCCROOT)
+AVRDUDE_CONF ?= -C$(TOOLROOT)/avr/etc/avrdude.conf
+
+# Default filename for the selected target
+FILENAME     ?= $(PROGRAM)_$(TARGET).hex
+
+# These are the parameters for a usb-based STK500v2 programmer.
+# Exact type unknown.  (historical Makefile values.)
+#ISPTOOL	   = stk500v2
+#ISPPORT	   =  usb
+#ISPSPEED   = -b 115200
+#
+#
+# These are parameters for using an Arduino with the ArduinoISP sketch
+#  as the programmer.  On a mac, for a particular Uno as programmer.
+ISPTOOL	?= stk500v1
+ISPPORT	?= /dev/tty.usbserial-FTD61T6Q
+ISPSPEED ?= -b19200
+
+
+
+# Not all chips have EFUSE.
+
+ifdef EFUSE
+EFUSE_CMD= -U efuse:w:0x$(EFUSE):m
+endif
+
+# Default lock fuse configuration (NO lock)
+LOCKFUSE ?= 2f# APP protect mode 1, BL protect mode 1
+
+#
+# avrdude commands to erase chip, unlock memory, and program fuses.
+#
+ISPFUSES =	-e -u -U lock:w:0x$(LOCKFUSE):m $(EFUSE_CMD) \
+	 	-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
+
+
+#
+# avrdude commands to program the new bootloader, and protect the bootloader
+# space from accidental SPM writes.  Note: "2f" allows boot section to be read
+# by the application, which is different than the arduino default.
+#
+ISPFLASH =	-U flash:w:$(FILENAME) -U lock:w:$(LOCKFUSE):m
+
+# There are certain complicated caused by the fact that the default state
+# of a fuse is a "1" rather than a "0", especially with respect to fuse bits
+# that have not been implemented.  Those would normally not be included, but
+# unimplemented fuses still default to being "1"
+#
+# 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.
+
+isp: $(FILENAME)
+	$(AVRDUDE_ROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
+              -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
+	$(ISPFUSES) \
+	$(ISPFLASH)

+ 346 - 0
optiboot/Makefile.mcudude

@@ -0,0 +1,346 @@
+#/*
+# * These are the CPU targets from Hans "MCUdude"
+# * MightyCore, MegaCore, MiniCore, and MajorCore
+# *  https://github.com/MCUdude
+# *
+# * This file has basic CPU defintions, while many possible combinations
+# * of AVR_FREQ, BAUD_RATE, and UART are built by a shell script.
+# */
+
+HELPTEXT += "\n target atmega1280    - ATmega1280 (100pin, 128k)\n"
+HELPTEXT += "target atmega88*     - Atmega88, ATmega88P, ATmega88PB\n"
+HELPTEXT += "target atmega16, atmega32, atmega64 - 40pin ATmegas\n"
+HELPTEXT += "target atmega164*, atmega324* - newer 40pin ATmegas\n"
+HELPTEXT += "target atmega644p, atmega1284* - newer 40pin ATmegas\n"
+HELPTEXT += "target atmega128, atmega1281, atmega2561 - 64pin ATmegas\n"
+HELPTEXT += "target atmega169, atmega329, atmega649\n"
+HELPTEXT += "target atmega640, atmega1280, atmega2560 - 100pin ATmegas\n"
+HELPTEXT += "target atmega162\n"
+HELPTEXT += "target atmega3290, atmega6490\n"
+HELPTEXT += "target atmega8515,atmega8535 - legacy 40pin chips\n"
+
+
+#ATmega16/A
+atmega16: TARGET = atmega16
+atmega16: MCU_TARGET = atmega16
+atmega16: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega16: AVR_FREQ ?= 16000000L
+atmega16: $(PROGRAM)_atmega16_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega16: $(PROGRAM)_atmega16_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega16a: atmega16
+
+#ATmega64/A
+atmega64: TARGET = atmega64
+atmega64: MCU_TARGET = atmega64
+atmega64: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega64: AVR_FREQ ?= 16000000L
+atmega64: $(PROGRAM)_atmega64_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega64: $(PROGRAM)_atmega64_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega64a: atmega64
+
+#ATmega88P/PA
+atmega88p: TARGET = atmega88p
+atmega88p: MCU_TARGET = atmega88p
+atmega88p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega88p: AVR_FREQ ?= 16000000L 
+atmega88p: $(PROGRAM)_atmega88p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega88p: $(PROGRAM)_atmega88p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega88pa: atmega88p
+
+#ATmega8PB
+atmega88pb: TARGET = atmega88pb
+atmega88pb: MCU_TARGET = atmega88pb
+atmega88pb: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega88pb: AVR_FREQ ?= 16000000L
+atmega88pb: $(PROGRAM)_atmega88pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega88pb: $(PROGRAM)_atmega88pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega128/A
+atmega128: TARGET = atmega128
+atmega128: MCU_TARGET = atmega128
+atmega128: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega128: AVR_FREQ ?= 16000000L
+atmega128: $(PROGRAM)_atmega128_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega128: $(PROGRAM)_atmega128_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega128a: atmega128
+
+#ATmega162
+atmega162: TARGET = atmega162
+atmega162: MCU_TARGET = atmega162
+atmega162: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega162: AVR_FREQ ?= 16000000L
+atmega162: $(PROGRAM)_atmega162_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega162: $(PROGRAM)_atmega162_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega164/A
+atmega164a: TARGET = atmega164a
+atmega164a: MCU_TARGET = atmega164a
+atmega164a: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega164a: AVR_FREQ ?= 16000000L
+atmega164a: $(PROGRAM)_atmega164a_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega164a: $(PROGRAM)_atmega164a_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega164: atmega164a
+
+#ATmega164P/PA
+atmega164p: TARGET = atmega164p
+atmega164p: MCU_TARGET = atmega164p
+atmega164p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega164p: AVR_FREQ ?= 16000000L
+atmega164p: $(PROGRAM)_atmega164p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega164p: $(PROGRAM)_atmega164p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega164pa: atmega164p
+
+#ATmega168/A
+#atmega168: TARGET = atmega168
+#atmega168: MCU_TARGET = atmega168
+#atmega168: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+#atmega168: AVR_FREQ ?= 16000000L 
+#atmega168: $(PROGRAM)_atmega168_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+#ifndef PRODUCTION
+#atmega168: $(PROGRAM)_atmega168_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+#endif
+atmega168a: atmega168
+
+#ATmega168P/PA
+atmega168p: TARGET = atmega168p
+atmega168p: MCU_TARGET = atmega168p
+atmega168p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega168p: AVR_FREQ ?= 16000000L 
+atmega168p: $(PROGRAM)_atmega168p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega168p: $(PROGRAM)_atmega168p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega168pa: atmega168p
+
+#ATmega168PB
+atmega168pb: TARGET = atmega168pb
+atmega168pb: MCU_TARGET = atmega168pb
+atmega168pb: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega168pb: AVR_FREQ ?= 16000000L 
+atmega168pb: $(PROGRAM)_atmega168pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega168pb: $(PROGRAM)_atmega168pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega169/A
+atmega169: TARGET = atmega169
+atmega169: MCU_TARGET = atmega169
+atmega169: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega169: AVR_FREQ ?= 16000000L
+atmega169: $(PROGRAM)_atmega169_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega169: $(PROGRAM)_atmega169_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega169a: atmega169
+
+#ATmega169P/PA
+atmega169p: TARGET = atmega169p
+atmega169p: MCU_TARGET = atmega169p
+atmega169p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega169p: AVR_FREQ ?= 16000000L
+atmega169p: $(PROGRAM)_atmega169p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega169p: $(PROGRAM)_atmega169p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega169pa: atmega169
+
+#ATmega324A
+atmega324a: TARGET = atmega324a
+atmega324a: MCU_TARGET = atmega324a
+atmega324a: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega324a: AVR_FREQ ?= 16000000L
+atmega324a: $(PROGRAM)_atmega324a_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega324a: $(PROGRAM)_atmega324a_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega324: atmega324a
+
+#ATmega324P
+atmega324p: TARGET = atmega324p
+atmega324p: MCU_TARGET = atmega324p
+atmega324p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega324p: AVR_FREQ ?= 16000000L
+atmega324p: $(PROGRAM)_atmega324p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega324p: $(PROGRAM)_atmega324p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega324PA
+atmega324pa: TARGET = atmega324pa
+atmega324pa: MCU_TARGET = atmega324pa
+atmega324pa: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega324pa: AVR_FREQ ?= 16000000L
+atmega324pa: $(PROGRAM)_atmega324pa_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega324pa: $(PROGRAM)_atmega324pa_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega324PB
+atmega324pb: TARGET = atmega324pb
+atmega324pb: MCU_TARGET = atmega324pb
+atmega324pb: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega324pb: AVR_FREQ ?= 16000000L
+atmega324pb: $(PROGRAM)_atmega324pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega324pb: $(PROGRAM)_atmega324pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega328PB
+atmega328pb: TARGET = atmega328pb
+atmega328pb: MCU_TARGET = atmega328pb
+atmega328pb: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega328pb: AVR_FREQ ?= 16000000L
+atmega328pb: $(PROGRAM)_atmega328pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega328pb: $(PROGRAM)_atmega328pb_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega329/A
+atmega329: TARGET = atmega329
+atmega329: MCU_TARGET = atmega329
+atmega329: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega329: AVR_FREQ ?= 16000000L
+atmega329: $(PROGRAM)_atmega329_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega329: $(PROGRAM)_atmega329_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega329a: atmega329
+
+#ATmega329P/PA
+atmega329p: TARGET = atmega329p
+atmega329p: MCU_TARGET = atmega329p
+atmega329p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega329p: AVR_FREQ ?= 16000000L
+atmega329p: $(PROGRAM)_atmega329p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega329p: $(PROGRAM)_atmega329p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega329pa: atmega329p
+
+#ATmega640
+atmega640: TARGET = atmega640
+atmega640: MCU_TARGET = atmega640
+atmega640: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega640: AVR_FREQ ?= 16000000L
+atmega640: $(PROGRAM)_atmega640_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega640: $(PROGRAM)_atmega640_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega649
+atmega649: TARGET = atmega649
+atmega649: MCU_TARGET = atmega649
+atmega649: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega649: AVR_FREQ ?= 16000000L
+atmega649: $(PROGRAM)_atmega649_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega649: $(PROGRAM)_atmega649_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega649P
+atmega649p: TARGET = atmega649p
+atmega649p: MCU_TARGET = atmega649p
+atmega649p: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega649p: AVR_FREQ ?= 16000000L
+atmega649p: $(PROGRAM)_atmega649p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega649p: $(PROGRAM)_atmega649p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega1281
+atmega1281: TARGET = atmega1281
+atmega1281: MCU_TARGET = atmega1281
+atmega1281: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega1281: AVR_FREQ ?= 16000000L
+atmega1281: $(PROGRAM)_atmega1281_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega1281: $(PROGRAM)_atmega1281_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega2561
+atmega2561: TARGET = atmega2561
+atmega2561: MCU_TARGET = atmega2561
+atmega2561: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega2561: AVR_FREQ ?= 16000000L
+atmega2561: $(PROGRAM)_atmega2561_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega2561: $(PROGRAM)_atmega2561_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega3290
+atmega3290: TARGET = atmega3290
+atmega3290: MCU_TARGET = atmega3290
+atmega3290: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega3290: AVR_FREQ ?= 16000000L
+atmega3290: $(PROGRAM)_atmega3290_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega3290: $(PROGRAM)_atmega3290_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega3290P/PA
+atmega3290p: TARGET = atmega3290p
+atmega3290p: MCU_TARGET = atmega3290p
+atmega3290p: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega3290p: AVR_FREQ ?= 16000000L
+atmega3290p: $(PROGRAM)_atmega3290p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega3290p: $(PROGRAM)_atmega3290p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+atmega3290pa: atmega3290p
+
+#ATmega6490
+atmega6490: TARGET = atmega6490
+atmega6490: MCU_TARGET = atmega6490
+atmega6490: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega6490: AVR_FREQ ?= 16000000L
+atmega6490: $(PROGRAM)_atmega6490_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega6490: $(PROGRAM)_atmega6490_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega6490P
+atmega6490p: TARGET = atmega6490p
+atmega6490p: MCU_TARGET = atmega6490p
+atmega6490p: CFLAGS += $(COMMON_OPTIONS) -DBIGBOOT $(UART_CMD)
+atmega6490p: AVR_FREQ ?= 16000000L
+atmega6490p: $(PROGRAM)_atmega6490p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega6490p: $(PROGRAM)_atmega6490p_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega8515
+atmega8515: TARGET = atmega8515
+atmega8515: MCU_TARGET = atmega8515
+atmega8515: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega8515: AVR_FREQ ?= 16000000L
+atmega8515: $(PROGRAM)_atmega8515_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega8515: $(PROGRAM)_atmega8515_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+
+#ATmega8535
+atmega8535: TARGET := atmega8535
+atmega8535: MCU_TARGET = atmega8535
+atmega8535: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega8535: AVR_FREQ ?= 16000000L
+atmega8535: $(PROGRAM)_atmega8535_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).hex
+ifndef PRODUCTION
+atmega8535: $(PROGRAM)_atmega8535_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ).lst
+endif
+

+ 225 - 0
optiboot/Makefile.mega0

@@ -0,0 +1,225 @@
+# Makefile for AVR Mega-0 (4809), Tiny-0, and Tiny-1 version of Optiboot
+# Bill Westfield, 2019
+# $Id$
+#
+# Edit History
+# Sep-2019 refactor from the normal AVR Makefile.
+# * Copyright 2013-2019 by Bill Westfield.  Part of Optiboot.
+# * This software is licensed under version 2 of the Gnu Public Licence.
+# * See optiboot.c for details.
+
+HELPTEXT = "\n"
+#----------------------------------------------------------------------
+#
+# program name should not be changed...
+PROGRAM    = optiboot_x
+MF:= $(MAKEFILE_LIST)
+
+# defaults
+MCU_TARGET = atmega4809
+
+ifdef BIGBOOT
+LDSECTIONS  = -Wl,-section-start=.text=0 \
+	      -Wl,--section-start=.application=0x400 \
+	      -Wl,--section-start=.version=0x3fe
+else
+LDSECTIONS  = -Wl,-section-start=.text=0 \
+	      -Wl,--section-start=.application=0x200 \
+	      -Wl,--section-start=.version=0x1fe
+endif
+
+BAUD_RATE=115200
+
+#AVRGCCROOT =
+AVRDUDE_CONF =
+
+# export symbols to recursive makes (for ISP)
+export
+
+#
+# End of build environment code.
+
+
+CC         = $(AVRGCCROOT)avr-gcc
+RCC        = $(abspath $(CC))
+#$(info wildcard ("$(wildcard $(CC))",""))
+ifndef PRODUCTION
+$(info Using Compiler at: ${RCC})
+endif
+
+
+# If we have a PACKS directory specified, we should use it...
+ifdef PACKS
+PACK_OPT= -I "$(PACKS)/include/" -B "$(PACKS)/gcc/dev/$*"
+ifndef PRODUCTION
+$(info   and Chip-defining PACKS at ${PACKS})
+endif
+endif
+
+
+OPTIMIZE = -Os -fno-split-wide-types -mrelax
+
+# Override is only needed by avr-lib build system.
+
+override CFLAGS  = -g -Wall $(OPTIMIZE)
+override LDFLAGS = $(LDSECTIONS) -Wl,--relax -nostartfiles -nostdlib
+
+OBJCOPY        = $(AVRGCCROOT)avr-objcopy
+OBJDUMP        = $(AVRGCCROOT)avr-objdump
+SIZE           = $(AVRGCCROOT)avr-size
+
+include parse_options.mk
+
+.PRECIOUS: optiboot_%.elf
+
+ifndef PRODUCTION
+LISTING= $(OBJDUMP) -S 
+else
+LISTING= @true
+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 atmega4809 UARTTX=A4 LED=D0"
+#---------------------------------------------------------------------------
+#
+# Mega0, tiny0, tiny1 don't really have any chip-specific requirements.
+#
+# Note about fuses:
+#  The fuses are defined in the source code.  There are 9!
+#  Be sure to use a programmer that will program the fuses from the object file.
+#
+#---------------------------------------------------------------------------
+#
+
+HELPTEXT += "\n-------------\n\n"
+
+
+optiboot_%.hex: optiboot_%.elf
+	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O ihex $< $@
+	@echo Bare Bootloader size
+	$(SIZE) $@
+#
+# Note that the .application section is not normally copied to the
+#  .hex file.  The .application section is useful for detecting growth
+#  beyond 512 bytes, and for being a target for starting the
+#  application, and for referencing certain otherwise-unused variables
+#  so they aren't optimized away, but all of that happens during
+#  compilation or link, and the code doesn't need to to actually be
+#  present in the binary/hex files (where it might interfere with easy
+#  merging with a real application.)
+# (including it in the .application may be useful for debugging, though)
+#	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -j .application -O ihex $< $@
+
+optiboot_%.elf:	optiboot_x.c FORCE
+	$(CC) $(CFLAGS) $(CPU_OPTIONS) $(LED_OPTIONS) $(UART_OPTIONS) $(COMMON_OPTIONS) $(LDFLAGS) $(PACK_OPT) -mmcu=$* -o $@ $<
+	@echo Bootloader size with skeleton App
+	@$(SIZE) $@
+	$(LISTING) $@ > optiboot_$*.lst
+
+
+#---------------------------------------------------------------------------
+# "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
+#---------------------------------------------------------------------------
+
+atmega%:
+	$(MAKE) -f $(MF) optiboot_atmega$*.hex
+
+attiny%:
+	$(MAKE) -f $(MF) optiboot_attiny$*.hex
+
+HELPTEXT += "target optiboot_*.hex - Any approriate mega-0, tiny-0, or tiny-1\n"
+HELPTEXT += "                          ie: optiboot_atmega4809\n"
+HELPTEXT += "target drazzy402,412 - Dr Azzy's 8pin dev boards.\n"
+drazzy%2:
+	$(MAKE) -f $(MF) optiboot_attiny$*2.hex UARTTX=A1 TIMEOUT=8 LED=A7
+
+HELPTEXT += "target drazzy*4      - Dr Azzy's 14pin dev boards.\n"
+drazzy%4:
+	$(MAKE) -f $(MF) optiboot_attiny$*4.hex UARTTX=B2 TIMEOUT=8 LED=A7
+
+HELPTEXT += "target drazzy*6      - Dr Azzy's 20pin dev boards.\n"
+drazzy%6:
+	$(MAKE) -f $(MF) optiboot_attiny$*6.hex UARTTX=B2 TIMEOUT=8 LED=A7
+
+HELPTEXT += "target drazzy*7      - Dr Azzy's 24pin dev boards.\n"
+drazzy%7:
+	$(MAKE) -f $(MF) optiboot_attiny$*7.hex UARTTX=B2 TIMEOUT=8 LED=A7
+
+HELPTEXT += "target curiosity1607 - Microchip ATtiny1607 Curiosity Nano.\n"
+curiosity1607:
+	$(MAKE) -f $(MF) optiboot_attiny1607.hex UARTTX=B2 TIMEOUT=8 LED=B7 LED_INVERT=1
+
+HELPTEXT += "target curiosity4809 - Microchip ATmega4809 Curiosity Nano.\n"
+curiosity4809:
+	$(MAKE) -f $(MF) optiboot_atmega4809.hex UARTTX=B0 TIMEOUT=8 LED=F5 LED_INVERT=1
+
+HELPTEXT += "target xplained416   - Microchip ATtiny416 Xplained Nano.\n"
+xplained416:
+	$(MAKE) -f $(MF) optiboot_attiny416.hex UARTTX=A1 TIMEOUT=8 LED=B5 LED_INVERT=1 BAUD_RATE=57600
+
+HELPTEXT += "target xplained817   - Microchip ATtiny817 Xplained Mini.\n"
+xplained817:
+	$(MAKE) -f $(MF) optiboot_attiny817.hex UARTTX=B2 TIMEOUT=8 LED=C0 BAUD_RATE=57600
+
+HELPTEXT += "target xplained4809  - Microchip ATmega4809 Xplained Pro.\n"
+xplained4809:
+	$(MAKE) -f $(MF) optiboot_atmega4809.hex UARTTX=C0 TIMEOUT=8 LED=B5 LED_INVERT=1 BAUD_RATE=115200
+
+HELPTEXT += "target freeduino4809 - WestfW ATmega4809 Uno-style board.\n"
+freeduino4809:
+	$(MAKE) -f $(MF) optiboot_atmega4809.hex UARTTX=B4 TIMEOUT=1 LED=D6 RESETPIN=1
+
+HELPTEXT += "target freeduino4809chip - WestfW ATmega4809 40pin DIP boards.\n"
+freeduino4809chip:
+	$(MAKE) -f $(MF) optiboot_atmega4809.hex UARTTX=A4 TIMEOUT=1 LED=A7 RESETPIN=1
+
+#---------------------------------------------------------------------------
+#
+# Generic build instructions
+#
+
+FORCE:
+
+isp: $(TARGET) FORCE
+	"$(MAKE)" -f Makefile.isp isp TARGET=$(TARGET)
+
+isp-stk500: $(PROGRAM)_$(TARGET).hex
+	$(STK500-1)
+	$(STK500-2)
+
+#windows "rm" is dumb and objects to wildcards that don't exist
+clean:
+	@touch  __temp_.o __temp_.elf __temp_.lst __temp_.map
+	@touch  __temp_.sym __temp_.lss __temp_.eep __temp_.srec
+	@touch __temp_.bin __temp_.hex __temp_.tmp.sh
+	rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex *.tmp.sh
+
+version:
+	$(CC) --version | head -1
+	@grep "define OPTIBOOT_...VER" $(PROGRAM).c 
+
+clean_asm:
+	rm -rf *.lst
+
+%.lst: %.elf FORCE
+	$(OBJDUMP) -h -S $< > $@
+
+%.srec: %.elf FORCE
+	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O srec $< $@
+
+%.bin: %.elf FORCE
+	$(OBJCOPY) -j .text -j .data -j .version --set-section-flags .version=alloc,load -O binary $< $@
+
+help:
+	@echo -e $(HELPTEXT)

+ 1485 - 0
optiboot/Makefile.tiny

@@ -0,0 +1,1485 @@
+#-------------------------------
+# ATtiny 1634, Base instructions
+#-------------------------------
+
+HELPTEXT += "\n target attiny1634    - atttiny1634at<freq>  attiny1634at<freq>ser1\n"
+HELPTEXT += "                     - atttiny1634at8_5v  attiny1634at8_5vser1\n"
+
+attiny1634:	TARGET = attiny1634
+attiny1634:	MCU_TARGET = attiny1634
+attiny1634:	LED_CMD ?= -DLED=C0
+attiny1634: CFLAGS += $(COMMON_OPTIONS) -DVIRTUAL_BOOT_PARTITION -DFOURPAGEERASE $(UART_CMD)
+attiny1634: AVR_FREQ ?= 8000000L
+attiny1634: $(PROGRAM)_attiny1634.hex
+ifndef PRODUCTION
+attiny1634: $(PROGRAM)_attiny1634.lst
+endif
+
+
+#-----------------------
+# ATtiny 1634, UART 0
+#-----------------------
+attiny1634at12:
+	"$(MAKE)" attiny1634	AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_12000000L.lst
+endif
+
+attiny1634at16:
+	"$(MAKE)" attiny1634	AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_16000000L.lst
+endif
+
+attiny1634at8:
+	"$(MAKE)" attiny1634	AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_8000000L.lst
+endif
+
+attiny1634at8_int:
+	"$(MAKE)" attiny1634	AVR_FREQ=8000000L BAUD_RATE=57600 LOWERCAL=9
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_8000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_8000000L_int.lst
+endif
+
+attiny1634at1:
+	"$(MAKE)" attiny1634	AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_1000000L.lst
+endif
+
+attiny1634at1_int:
+	"$(MAKE)" attiny1634	AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=5
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_1000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_1000000L_int.lst
+endif
+
+attiny1634at737:
+	"$(MAKE)" attiny1634	AVR_FREQ=7372800L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_7372800L.lst
+endif
+
+attiny1634at921:
+	"$(MAKE)" attiny1634	AVR_FREQ=9216000L  BAUD_RATE=57600
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_9216000L.lst
+endif
+
+attiny1634at110:
+	"$(MAKE)" attiny1634	AVR_FREQ=11059200L
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_11059200L.lst
+endif
+
+attiny1634at147:
+	"$(MAKE)" attiny1634	AVR_FREQ=14745600L
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_14745600L.lst
+endif
+
+
+#-----------------------
+# ATtiny 1634, UART 1
+#-----------------------
+
+attiny1634at12ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=12000000L UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_12000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_12000000L_ser1.lst
+endif
+
+attiny1634at16ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=16000000L UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_16000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_16000000L_ser1.lst
+endif
+
+attiny1634at8ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=8000000L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_8000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_8000000L_ser1.lst
+endif
+
+attiny1634at8_intser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=8000000L BAUD_RATE=57600 UART=1 LOWERCAL=9
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_8000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_8000000L_ser1_int.lst
+endif
+
+attiny1634at1ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=1000000L BAUD_RATE=4800 UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_1000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_1000000L_ser1.lst
+endif
+
+attiny1634at1_intser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=1000000L BAUD_RATE=4800 UART=1 LOWERCAL=5
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_1000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_1000000L_ser1_int.lst
+endif
+
+attiny1634at737ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=7372800L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_7372800L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_7372800L_ser1.lst
+endif
+
+attiny1634at921ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=9216000L  BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_9216000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_9216000L_ser1.lst
+endif
+
+attiny1634at110ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=11059200L UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_11059200L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_11059200L_ser1.lst
+endif
+
+attiny1634at147ser1:
+	"$(MAKE)" attiny1634	AVR_FREQ=14745600L UART=1
+	mv $(PROGRAM)_attiny1634.hex $(PROGRAM)_attiny1634_14745600L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny1634.lst $(PROGRAM)_attiny1634_14745600L_ser1.lst
+endif
+
+
+#--------------------------------
+# ATtiny 841, base instructions
+#-------------------------------
+
+HELPTEXT += "target attiny841     - atttiny841at<freq>  attiny841at<freq>ser1\n"
+HELPTEXT += "                     - atttiny841at8_5v  attiny841at8_5vser1\n"
+HELPTEXT += "                     - atttiny841at<freq>noLED\n"
+
+attiny841: TARGET = attiny841
+attiny841: MCU_TARGET = attiny841
+attiny841: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DFOURPAGEERASE' $(UART_CMD)
+attiny841: AVR_FREQ ?= 8000000L
+attiny841: $(PROGRAM)_attiny841.hex
+ifndef PRODUCTION
+attiny841: $(PROGRAM)_attiny841.lst
+endif
+
+#-----------------------
+# ATtiny 841, UART 0
+#-----------------------
+attiny841at184:
+	$(MAKE) attiny841	 AVR_FREQ=18432000L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_18432000L.lst
+endif
+
+attiny841at147:
+	$(MAKE) attiny841	 AVR_FREQ=14745600L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_14745600L.lst
+endif
+
+attiny841at110:
+	$(MAKE) attiny841	 AVR_FREQ=11059200L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_11059200L.lst
+endif
+
+attiny841at921:
+	$(MAKE) attiny841	 AVR_FREQ=9216000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_9216000L.lst
+endif
+
+attiny841at737:
+	$(MAKE) attiny841	 AVR_FREQ=7372800L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_7372800L.lst
+endif
+
+attiny841at20:
+	$(MAKE) attiny841	 AVR_FREQ=20000000L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_20000000L.lst
+endif
+
+attiny841at16:
+	$(MAKE) attiny841	 AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_16000000L.lst
+endif
+
+attiny841at12:
+	$(MAKE) attiny841	 AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_12000000L.lst
+endif
+
+attiny841at8:
+	$(MAKE) attiny841	 AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_8000000L.lst
+endif
+
+attiny841at8_int:
+	$(MAKE) attiny841	 AVR_FREQ=8000000L BAUD_RATE=57600 LOWERCAL=7
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_8000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_8000000L_int.lst
+endif
+
+attiny841at1:
+	$(MAKE) attiny841	 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_1000000L.lst
+endif
+
+attiny841at1_int:
+	$(MAKE) attiny841	 AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=4
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_1000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_1000000L_int.lst
+endif
+
+#-----------------------
+# ATtiny 841, UART 1
+#-----------------------
+attiny841at184ser1:
+	$(MAKE) attiny841	 AVR_FREQ=18432000L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_18432000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_18432000L_ser1.lst
+endif
+
+attiny841at147ser1:
+	$(MAKE) attiny841	 AVR_FREQ=14745600L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_14745600L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_14745600L_ser1.lst
+endif
+
+attiny841at110ser1:
+	$(MAKE) attiny841	 AVR_FREQ=11059200L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_11059200L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_11059200L_ser1.lst
+endif
+
+attiny841at921ser1:
+	$(MAKE) attiny841	 AVR_FREQ=9216000L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_9216000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_9216000L_ser1.lst
+endif
+
+attiny841at737ser1:
+	$(MAKE) attiny841	 AVR_FREQ=7372800L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_7372800L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_7372800L_ser1.lst
+endif
+
+attiny841at20ser1:
+	$(MAKE) attiny841	 AVR_FREQ=20000000L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_20000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_20000000L_ser1.lst
+endif
+
+attiny841at16ser1:
+	$(MAKE) attiny841	 AVR_FREQ=16000000L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_16000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_16000000L_ser1.lst
+endif
+
+attiny841at12ser1:
+	$(MAKE) attiny841	 AVR_FREQ=12000000L UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_12000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_12000000L_ser1.lst
+endif
+
+attiny841at8ser1:
+	$(MAKE) attiny841	 AVR_FREQ=8000000L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_8000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_8000000L_ser1.lst
+endif
+attiny841at8_intser1:
+	$(MAKE) attiny841	AVR_FREQ=8000000L BAUD_RATE=57600 LOWERCAL=7 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_8000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_8000000L_ser1_int.lst
+endif
+
+attiny841at1ser1:
+	$(MAKE) attiny841	 AVR_FREQ=1000000L BAUD_RATE=4800 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_1000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_1000000L_ser1.lst
+endif
+attiny841at1_intser1:
+	$(MAKE) attiny841	 AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=4 UART=1
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_1000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_1000000L_ser1_int.lst
+endif
+
+#-----------------------
+# ATtiny 841, UART 0, no LED
+# There's no noLED definitions for 1634 because the larger page size
+# on the 1634 means that you don't gain any usable flash from it.
+#-----------------------
+
+attiny841at20noLED:
+	$(MAKE) attiny841	 AVR_FREQ=20000000L LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_20000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_20000000L_noLED.lst
+endif
+
+attiny841at16noLED:
+	$(MAKE) attiny841	 AVR_FREQ=16000000L LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_16000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_16000000L_noLED.lst
+endif
+
+attiny841at8noLED:
+	$(MAKE) attiny841	 AVR_FREQ=8000000L  BAUD_RATE=57600 LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny841.hex $(PROGRAM)_attiny841_8000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny841.lst $(PROGRAM)_attiny841_8000000L_noLED.lst
+endif
+
+#--------------------------------
+# ATtiny 441, base instructions
+#-------------------------------
+
+HELPTEXT += "target attiny441     - atttiny441at<freq>  attiny441at<freq>ser1\n"
+HELPTEXT += "                     - atttiny441at8_5v  attiny441at8_5vser1\n"
+HELPTEXT += "                     - atttiny441at<freq>noLED\n"
+
+attiny441: TARGET = attiny441
+attiny441: MCU_TARGET = attiny441
+attiny441: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DFOURPAGEERASE' $(UART_CMD)
+attiny441: AVR_FREQ ?= 8000000L
+attiny441: $(PROGRAM)_attiny441.hex
+ifndef PRODUCTION
+attiny441: $(PROGRAM)_attiny441.lst
+endif
+
+#-----------------------
+# ATtiny 441, UART 0
+#-----------------------
+attiny441at184:
+	$(MAKE) attiny441	 AVR_FREQ=18432000L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_18432000L.lst
+endif
+
+attiny441at147:
+	$(MAKE) attiny441	 AVR_FREQ=14745600L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_14745600L.lst
+endif
+
+attiny441at110:
+	$(MAKE) attiny441	 AVR_FREQ=11059200L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_11059200L.lst
+endif
+
+attiny441at921:
+	$(MAKE) attiny441	 AVR_FREQ=9216000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_9216000L.lst
+endif
+
+attiny441at737:
+	$(MAKE) attiny441	 AVR_FREQ=7372800L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_7372800L.lst
+endif
+
+attiny441at20:
+	$(MAKE) attiny441	 AVR_FREQ=20000000L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_20000000L.lst
+endif
+
+attiny441at16:
+	$(MAKE) attiny441	 AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_16000000L.lst
+endif
+
+attiny441at12:
+	$(MAKE) attiny441	 AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_12000000L.lst
+endif
+
+attiny441at8:
+	$(MAKE) attiny441	 AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_8000000L.lst
+endif
+
+attiny441at8_int:
+	$(MAKE) attiny441	 AVR_FREQ=8000000L LOWERCAL=7 BAUD_RATE=57600
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_8000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_8000000L_int.lst
+endif
+
+attiny441at1:
+	$(MAKE) attiny441	 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_1000000L.lst
+endif
+
+attiny441at1_int:
+	$(MAKE) attiny441	 AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=4
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_1000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_1000000L_int.lst
+endif
+
+
+#-----------------------
+# ATtiny 441, UART 1
+#-----------------------
+attiny441at184ser1:
+	$(MAKE) attiny441	 AVR_FREQ=18432000L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_18432000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_18432000L_ser1.lst
+endif
+
+attiny441at147ser1:
+	$(MAKE) attiny441	 AVR_FREQ=14745600L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_14745600L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_14745600L_ser1.lst
+endif
+
+attiny441at110ser1:
+	$(MAKE) attiny441	 AVR_FREQ=11059200L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_11059200L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_11059200L_ser1.lst
+endif
+
+attiny441at921ser1:
+	$(MAKE) attiny441	 AVR_FREQ=9216000L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_9216000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_9216000L_ser1.lst
+endif
+
+attiny441at737ser1:
+	$(MAKE) attiny441	 AVR_FREQ=7372800L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_7372800L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_7372800L_ser1.lst
+endif
+
+attiny441at20ser1:
+	$(MAKE) attiny441	 AVR_FREQ=20000000L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_20000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_20000000L_ser1.lst
+endif
+
+attiny441at16ser1:
+	$(MAKE) attiny441	 AVR_FREQ=16000000L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_16000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_16000000L_ser1.lst
+endif
+
+attiny441at12ser1:
+	$(MAKE) attiny441	 AVR_FREQ=12000000L UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_12000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_12000000L_ser1.lst
+endif
+
+attiny441at8ser1:
+	$(MAKE) attiny441	 AVR_FREQ=8000000L BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_8000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_8000000L_ser1.lst
+endif
+
+attiny441at8_intser1:
+	$(MAKE) attiny441	 AVR_FREQ=8000000L LOWERCAL=7 BAUD_RATE=57600 UART=1
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_8000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_8000000L_ser1_int.lst
+endif
+
+
+attiny441at1ser1:
+	$(MAKE) attiny441	 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_1000000L_ser1.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_1000000L_ser1.lst
+endif
+
+attiny441at1_intser1:
+	$(MAKE) attiny441	 AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=4
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_1000000L_ser1_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_1000000L_ser1_int.lst
+endif
+
+
+
+#-----------------------
+# ATtiny 841, UART 0, no LED
+# There's no noLED definitions for 1634 because the larger page size
+# on the 1634 means that you don't gain any usable flash from it.
+#-----------------------
+
+attiny441at20noLED:
+	$(MAKE) attiny441	 AVR_FREQ=20000000L LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_20000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_20000000L_noLED.lst
+endif
+
+attiny441at16noLED:
+	$(MAKE) attiny441	 AVR_FREQ=16000000L LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_16000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_16000000L_noLED.lst
+endif
+
+attiny441at8noLED:
+	$(MAKE) attiny441	 AVR_FREQ=8000000L  BAUD_RATE=57600 LED_START_FLASHES=0
+	mv $(PROGRAM)_attiny441.hex $(PROGRAM)_attiny441_8000000L_noLED.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny441.lst $(PROGRAM)_attiny441_8000000L_noLED.lst
+endif
+
+#-------------------
+# ATtiny828 - only one speed since it doesn't support crystal.
+# If you want to use an external clock
+#--------------------
+
+HELPTEXT += "target attiny828     - atttiny828at<freq>  attiny841at8_5v\n"
+
+attiny828: TARGET = attiny828
+attiny828: MCU_TARGET = attiny828
+attiny828: CFLAGS += $(COMMON_OPTIONS)
+attiny828: AVR_FREQ ?= 8000000L
+attiny828: $(PROGRAM)_attiny828.hex
+ifndef PRODUCTION
+attiny828: $(PROGRAM)_attiny828.lst
+endif
+
+
+attiny828at8:
+	$(MAKE) attiny828 AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_8000000L.lst
+endif
+
+attiny828at12:
+	$(MAKE) attiny828 AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_12000000L.lst
+endif
+
+attiny828at16:
+	$(MAKE) attiny828 AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_16000000L.lst
+endif
+
+attiny828at20:
+	$(MAKE) attiny828 AVR_FREQ=20000000L
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_20000000L.lst
+endif
+
+attiny828at8_int:
+	$(MAKE) attiny828 AVR_FREQ=8000000L BAUD_RATE=57600 LOWERCAL=9
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_8000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_8000000L_int.lst
+endif
+
+attiny828at1:
+	$(MAKE) attiny828 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_1000000L.lst
+endif
+
+attiny828at1_int:
+	$(MAKE) attiny828 AVR_FREQ=1000000L BAUD_RATE=4800 LOWERCAL=5
+	mv $(PROGRAM)_attiny828.hex $(PROGRAM)_attiny828_1000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny828.lst $(PROGRAM)_attiny828_1000000L_int.lst
+endif
+#-------------------
+# ATtiny88 - only one speed since it doesn't support crystal.
+# If you want to use an external clock
+#--------------------
+
+HELPTEXT += "target attiny88     - atttiny88at<freq> \n"
+
+attiny88: TARGET = attiny88
+attiny88: MCU_TARGET = attiny88
+attiny88: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny88: AVR_FREQ ?= 8000000L
+attiny88: $(PROGRAM)_attiny88.hex
+ifndef PRODUCTION
+attiny88: $(PROGRAM)_attiny88.lst
+endif
+
+attiny88at20:
+	$(MAKE) attiny88 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_20000000L.lst
+endif
+
+
+attiny88at16:
+	$(MAKE) attiny88 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_16000000L.lst
+endif
+
+attiny88at12:
+	$(MAKE) attiny88 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_12000000L.lst
+endif
+
+attiny88at8:
+	$(MAKE) attiny88 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_8000000L.lst
+endif
+
+attiny88at4:
+	$(MAKE) attiny88 AVR_FREQ=4000000L BAUD_RATE=9600
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_4000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_4000000L.lst
+endif
+
+# adjusts prescaler - that's the value for CLKPR not division factor
+attiny88at4_int:
+	$(MAKE) attiny88 AVR_FREQ=4000000L BAUD_RATE=9600 PRESCALE=1
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_4000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_4000000L_int.lst
+endif
+
+attiny88at1:
+	$(MAKE) attiny88 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny88.hex $(PROGRAM)_attiny88_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny88.lst $(PROGRAM)_attiny88_1000000L.lst
+endif
+#-------------------
+# ATtiny48 - only one speed since it doesn't support crystal.
+# If you want to use an external clock
+#--------------------
+
+HELPTEXT += "target attiny48     - atttiny48at<freq> \n"
+
+attiny48: TARGET = attiny48
+attiny48: MCU_TARGET = attiny48
+attiny48: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny48: AVR_FREQ ?= 8000000L
+attiny48: $(PROGRAM)_attiny48.hex
+ifndef PRODUCTION
+attiny48: $(PROGRAM)_attiny48.lst
+endif
+
+attiny48at20:
+	$(MAKE) attiny48 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_20000000L.lst
+endif
+
+attiny48at16:
+	$(MAKE) attiny48 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_16000000L.lst
+endif
+
+attiny48at12:
+	$(MAKE) attiny48 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_12000000L.lst
+endif
+
+attiny48at8:
+	$(MAKE) attiny48 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_8000000L.lst
+endif
+
+attiny48at4:
+	$(MAKE) attiny48 AVR_FREQ=4000000L BAUD_RATE=9600
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_4000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_4000000L.lst
+endif
+
+# adjusts prescaler appropriately - that's the value for CLKPR, not prescale factor.
+attiny48at4_int:
+	$(MAKE) attiny48 AVR_FREQ=4000000L BAUD_RATE=9600 PRESCALE=1
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_4000000L_int.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_4000000L_int.lst
+endif
+
+attiny48at1:
+	$(MAKE) attiny48 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny48.hex $(PROGRAM)_attiny48_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny48.lst $(PROGRAM)_attiny48_1000000L.lst
+endif
+
+#-------------------
+# ATtiny85 - No LED (pins are scarce, and led blink routine would need to be adapted to x5 timer, and it saves us a page of flash)
+#--------------------
+
+HELPTEXT += "target attiny85     - attiny85at<freq> \n"
+
+attiny85: TARGET = attiny85
+attiny85: MCU_TARGET = attiny85
+attiny85: LED_START_FLASHES_CMD = '-DLED_START_FLASHES=0'
+attiny85: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny85: AVR_FREQ ?= 8000000L
+attiny85: $(PROGRAM)_attiny85.hex
+ifndef PRODUCTION
+attiny85: $(PROGRAM)_attiny85.lst
+endif
+
+
+attiny85at8:
+	$(MAKE) attiny85 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_8000000L.lst
+endif
+
+attiny85at1:
+	$(MAKE) attiny85 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_1000000L.lst
+endif
+attiny85at12:
+	$(MAKE) attiny85 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_12000000L.lst
+endif
+
+attiny85at16:
+	$(MAKE) attiny85 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_16000000L.lst
+endif
+
+attiny85at20:
+	$(MAKE) attiny85 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_20000000L.lst
+endif
+
+attiny85at737:
+	$(MAKE) attiny85 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_7372800L.lst
+endif
+
+attiny85at921:
+	$(MAKE) attiny85 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_9216000L.lst
+endif
+
+attiny85at110:
+	$(MAKE) attiny85 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_11059200L.lst
+endif
+
+attiny85at147:
+	$(MAKE) attiny85 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_14745600L.lst
+endif
+
+attiny85at184:
+	$(MAKE) attiny85 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny85.hex $(PROGRAM)_attiny85_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny85.lst $(PROGRAM)_attiny85_18432000L.lst
+endif
+
+#-------------------
+# ATtiny45 - No LED (pins are scarce, and led blink routine would need to be adapted to x5 timer, and it saves us a page of flash)
+#--------------------
+
+HELPTEXT += "target attiny45     - attiny45at<freq> \n"
+
+attiny45: TARGET = attiny45
+attiny45: MCU_TARGET = attiny45
+attiny45: LED_START_FLASHES_CMD = '-DLED_START_FLASHES=0'
+attiny45: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny45: AVR_FREQ ?= 8000000L
+attiny45: $(PROGRAM)_attiny45.hex
+ifndef PRODUCTION
+attiny45: $(PROGRAM)_attiny45.lst
+endif
+
+
+attiny45at8:
+	$(MAKE) attiny45 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_8000000L.lst
+endif
+
+attiny45at1:
+	$(MAKE) attiny45 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_1000000L.lst
+endif
+attiny45at12:
+	$(MAKE) attiny45 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_12000000L.lst
+endif
+
+attiny45at16:
+	$(MAKE) attiny45 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_16000000L.lst
+endif
+
+attiny45at20:
+	$(MAKE) attiny45 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_20000000L.lst
+endif
+
+attiny45at737:
+	$(MAKE) attiny45 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_7372800L.lst
+endif
+
+attiny45at921:
+	$(MAKE) attiny45 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_9216000L.lst
+endif
+
+attiny45at110:
+	$(MAKE) attiny45 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_11059200L.lst
+endif
+
+attiny45at147:
+	$(MAKE) attiny45 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_14745600L.lst
+endif
+
+attiny45at184:
+	$(MAKE) attiny45 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny45.hex $(PROGRAM)_attiny45_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny45.lst $(PROGRAM)_attiny45_18432000L.lst
+endif
+
+
+#-------------------
+# ATtiny84
+#--------------------
+
+HELPTEXT += "target attiny84     - attiny84at<freq> \n"
+
+attiny84: TARGET = attiny84
+attiny84: MCU_TARGET = attiny84
+attiny84: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny84: AVR_FREQ ?= 8000000L
+attiny84: $(PROGRAM)_attiny84.hex
+ifndef PRODUCTION
+attiny84: $(PROGRAM)_attiny84.lst
+endif
+
+
+attiny84at8:
+	$(MAKE) attiny84 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_8000000L.lst
+endif
+
+attiny84at1:
+	$(MAKE) attiny84 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_1000000L.lst
+endif
+
+attiny84at12:
+	$(MAKE) attiny84 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_12000000L.lst
+endif
+
+attiny84at16:
+	$(MAKE) attiny84 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_16000000L.lst
+endif
+
+attiny84at20:
+	$(MAKE) attiny84 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_20000000L.lst
+endif
+
+attiny84at737:
+	$(MAKE) attiny84 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_7372800L.lst
+endif
+
+attiny84at921:
+	$(MAKE) attiny84 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_9216000L.lst
+endif
+
+attiny84at110:
+	$(MAKE) attiny84 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_11059200L.lst
+endif
+
+attiny84at147:
+	$(MAKE) attiny84 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_14745600L.lst
+endif
+
+attiny84at184:
+	$(MAKE) attiny84 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny84.hex $(PROGRAM)_attiny84_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny84.lst $(PROGRAM)_attiny84_18432000L.lst
+endif
+
+#-------------------
+# ATtiny44
+#--------------------
+
+HELPTEXT += "target attiny44     - attiny44at<freq> \n"
+
+attiny44: TARGET = attiny44
+attiny44: MCU_TARGET = attiny44
+attiny44: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny44: AVR_FREQ ?= 8000000L
+attiny44: $(PROGRAM)_attiny44.hex
+ifndef PRODUCTION
+attiny44: $(PROGRAM)_attiny44.lst
+endif
+
+
+attiny44at8:
+	$(MAKE) attiny44 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_8000000L.lst
+endif
+
+attiny44at1:
+	$(MAKE) attiny44 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_1000000L.lst
+endif
+
+attiny44at12:
+	$(MAKE) attiny44 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_12000000L.lst
+endif
+
+attiny44at16:
+	$(MAKE) attiny44 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_16000000L.lst
+endif
+
+attiny44at20:
+	$(MAKE) attiny44 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_20000000L.lst
+endif
+
+attiny44at737:
+	$(MAKE) attiny44 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_7372800L.lst
+endif
+
+attiny44at921:
+	$(MAKE) attiny44 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_9216000L.lst
+endif
+
+attiny44at110:
+	$(MAKE) attiny44 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_11059200L.lst
+endif
+
+attiny44at147:
+	$(MAKE) attiny44 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_14745600L.lst
+endif
+
+attiny44at184:
+	$(MAKE) attiny44 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny44.hex $(PROGRAM)_attiny44_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny44.lst $(PROGRAM)_attiny44_18432000L.lst
+endif
+
+
+#-------------------
+# ATtiny861
+#--------------------
+
+HELPTEXT += "target attiny861     - attiny861at<freq> \n"
+
+attiny861: TARGET = attiny861
+attiny861: MCU_TARGET = attiny861
+attiny861: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny861: AVR_FREQ ?= 8000000L
+attiny861: $(PROGRAM)_attiny861.hex
+ifndef PRODUCTION
+attiny861: $(PROGRAM)_attiny861.lst
+endif
+
+
+attiny861at8:
+	$(MAKE) attiny861 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_8000000L.lst
+endif
+
+attiny861at1:
+	$(MAKE) attiny861 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_1000000L.lst
+endif
+
+attiny861at12:
+	$(MAKE) attiny861 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_12000000L.lst
+endif
+
+attiny861at16:
+	$(MAKE) attiny861 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_16000000L.lst
+endif
+
+attiny861at20:
+	$(MAKE) attiny861 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_20000000L.lst
+endif
+
+attiny861at737:
+	$(MAKE) attiny861 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_7372800L.lst
+endif
+
+attiny861at921:
+	$(MAKE) attiny861 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_9216000L.lst
+endif
+
+attiny861at110:
+	$(MAKE) attiny861 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_11059200L.lst
+endif
+
+attiny861at147:
+	$(MAKE) attiny861 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_14745600L.lst
+endif
+
+attiny861at184:
+	$(MAKE) attiny861 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny861.hex $(PROGRAM)_attiny861_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny861.lst $(PROGRAM)_attiny861_18432000L.lst
+endif
+
+#-------------------
+# ATtiny461
+#--------------------
+
+HELPTEXT += "target attiny461     - attiny461at<freq> \n"
+
+attiny461: TARGET = attiny461
+attiny461: MCU_TARGET = attiny461
+attiny461: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION' '-DSOFT_UART'
+attiny461: AVR_FREQ ?= 8000000L
+attiny461: $(PROGRAM)_attiny461.hex
+ifndef PRODUCTION
+attiny461: $(PROGRAM)_attiny461.lst
+endif
+
+
+attiny461at8:
+	$(MAKE) attiny461 AVR_FREQ=8000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_8000000L.lst
+endif
+
+attiny461at1:
+	$(MAKE) attiny461 AVR_FREQ=1000000L BAUD_RATE=2400
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_1000000L.lst
+endif
+
+attiny461at12:
+	$(MAKE) attiny461 AVR_FREQ=12000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_12000000L.lst
+endif
+
+attiny461at16:
+	$(MAKE) attiny461 AVR_FREQ=16000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_16000000L.lst
+endif
+
+attiny461at20:
+	$(MAKE) attiny461 AVR_FREQ=20000000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_20000000L.lst
+endif
+
+attiny461at737:
+	$(MAKE) attiny461 AVR_FREQ=7372800L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_7372800L.lst
+endif
+
+attiny461at921:
+	$(MAKE) attiny461 AVR_FREQ=9216000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_9216000L.lst
+endif
+
+attiny461at110:
+	$(MAKE) attiny461 AVR_FREQ=11059200L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_11059200L.lst
+endif
+
+attiny461at147:
+	$(MAKE) attiny461 AVR_FREQ=14745600L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_14745600L.lst
+endif
+
+attiny461at184:
+	$(MAKE) attiny461 AVR_FREQ=18432000L BAUD_RATE=19200
+	mv $(PROGRAM)_attiny461.hex $(PROGRAM)_attiny461_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny461.lst $(PROGRAM)_attiny461_18432000L.lst
+endif
+
+
+#-------------------
+# ATtiny167, ATtiny87 - has LIN UART
+#--------------------
+
+HELPTEXT += "target attiny167, attiny87\n"
+
+attiny167: TARGET = attiny167
+attiny167: MCU_TARGET = attiny167
+attiny167: AVR_FREQ ?= 8000000L
+attiny167: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION'
+attiny167: $(PROGRAM)_attiny167.hex
+ifndef PRODUCTION
+attiny167: $(PROGRAM)_attiny167.lst
+endif
+
+
+attiny87: TARGET = attiny87
+attiny87: MCU_TARGET = attiny87
+attiny87: CFLAGS += $(COMMON_OPTIONS) '-DVIRTUAL_BOOT_PARTITION'
+attiny87: AVR_FREQ ?= 8000000L
+attiny87: $(PROGRAM)_attiny87.hex
+ifndef PRODUCTION
+attiny87: $(PROGRAM)_attiny87.lst
+endif
+
+attiny167at184:
+	$(MAKE) attiny167	 AVR_FREQ=18432000L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_18432000L.lst
+endif
+
+attiny167at147:
+	$(MAKE) attiny167	 AVR_FREQ=14745600L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_14745600L.lst
+endif
+
+attiny167at110:
+	$(MAKE) attiny167	 AVR_FREQ=11059200L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_11059200L.lst
+endif
+
+attiny167at921:
+	$(MAKE) attiny167	 AVR_FREQ=9216000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_9216000L.lst
+endif
+
+attiny167at737:
+	$(MAKE) attiny167	 AVR_FREQ=7372800L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_7372800L.lst
+endif
+
+attiny167at20:
+	$(MAKE) attiny167	 AVR_FREQ=20000000L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_20000000L.lst
+endif
+
+attiny167at16:
+	$(MAKE) attiny167	 AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_16000000L.lst
+endif
+
+attiny167at12:
+	$(MAKE) attiny167	 AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_12000000L.lst
+endif
+
+attiny167at8:
+	$(MAKE) attiny167	 AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_8000000L.lst
+endif
+
+attiny167at1:
+	$(MAKE) attiny167	 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny167.hex $(PROGRAM)_attiny167_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny167.lst $(PROGRAM)_attiny167_1000000L.lst
+endif
+
+attiny87at184:
+	$(MAKE) attiny87	 AVR_FREQ=18432000L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_18432000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_18432000L.lst
+endif
+
+attiny87at147:
+	$(MAKE) attiny87	 AVR_FREQ=14745600L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_14745600L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_14745600L.lst
+endif
+
+attiny87at110:
+	$(MAKE) attiny87	 AVR_FREQ=11059200L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_11059200L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_11059200L.lst
+endif
+
+attiny87at921:
+	$(MAKE) attiny87	 AVR_FREQ=9216000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_9216000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_9216000L.lst
+endif
+
+attiny87at737:
+	$(MAKE) attiny87	 AVR_FREQ=7372800L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_7372800L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_7372800L.lst
+endif
+
+attiny87at20:
+	$(MAKE) attiny87	 AVR_FREQ=20000000L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_20000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_20000000L.lst
+endif
+
+attiny87at16:
+	$(MAKE) attiny87	 AVR_FREQ=16000000L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_16000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_16000000L.lst
+endif
+
+attiny87at12:
+	$(MAKE) attiny87	 AVR_FREQ=12000000L
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_12000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_12000000L.lst
+endif
+
+attiny87at8:
+	$(MAKE) attiny87	 AVR_FREQ=8000000L BAUD_RATE=57600
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_8000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_8000000L.lst
+endif
+
+attiny87at1:
+	$(MAKE) attiny87	 AVR_FREQ=1000000L BAUD_RATE=4800
+	mv $(PROGRAM)_attiny87.hex $(PROGRAM)_attiny87_1000000L.hex
+ifndef PRODUCTION
+	mv $(PROGRAM)_attiny87.lst $(PROGRAM)_attiny87_1000000L.lst
+endif

+ 292 - 0
optiboot/Makefile.usbmcus

@@ -0,0 +1,292 @@
+#/*
+# * These are the AVR-USB-MCUs
+# * soldered on Arduino Micro / Leonardo and similar boards representing the main IO-MCU
+# * or being used on Arduino Uno (Wifi) / Mega (2560) as USB to UART converter, the USB-MCU
+# * The USB (DFU)-Bootloader installed per default on these devices is REPLACED by Optiboot,
+# * thus supporting upload via USART1 (serial1) INSTEAD of USB!!!
+# * 
+# * https://github.com/Virtual-Java
+# *
+# * This file has basic CPU defintions, while many possible combinations
+# * of AVR_FREQ, BAUD_RATE, and UART are built by a shell script.
+# */
+
+
+HELPTEXT += "target atmega8/16/32u2, atmega16/32u4 - newer 32/44pin AVR-USB-MCUs \n"
+
+
+#-----------------------
+# ATmega 8u2
+#-----------------------
+#ATmega8u2
+atmega8u2atUART: TARGET = atmega8u2
+atmega8u2atUART: MCU_TARGET = atmega8u2
+atmega8u2atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega8u2atUART: AVR_FREQ ?= 16000000L
+atmega8u2atUART: $(PROGRAM)_atmega8u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega8u2atUART: $(PROGRAM)_atmega8u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega8u2:
+	"$(MAKE)" atmega8u2atUART UART?=1
+
+atmega8u2_isp: atmega8u2
+atmega8u2_isp: TARGET = atmega8u2
+atmega8u2_isp: MCU_TARGET = atmega8u2
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega8u2_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega8u2_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega8u2_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega8u2_isp: EFUSE ?= FE# = 2.7V brownout
+atmega8u2_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega8u2_isp: isp
+
+
+#-----------------------
+# ATmega 16u2
+#-----------------------
+#ATmega16u2
+atmega16u2atUART: TARGET = atmega16u2
+atmega16u2atUART: MCU_TARGET = atmega16u2
+atmega16u2atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega16u2atUART: AVR_FREQ ?= 16000000L
+atmega16u2atUART: $(PROGRAM)_atmega16u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega16u2atUART: $(PROGRAM)_atmega16u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega16u2:
+	"$(MAKE)" atmega16u2atUART UART?=1
+
+atmega16u2_isp: atmega16u2
+atmega16u2_isp: TARGET = atmega16u2
+atmega16u2_isp: MCU_TARGET = atmega16u2
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega16u2_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega16u2_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega16u2_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega16u2_isp: EFUSE ?= FE# = 2.7V brownout
+atmega16u2_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega16u2_isp: isp
+
+
+#-----------------------
+# ATmega 32u2
+#-----------------------
+#ATmega32u2
+atmega32u2atUART: TARGET = atmega32u2
+atmega32u2atUART: MCU_TARGET = atmega32u2
+atmega32u2atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega32u2atUART: AVR_FREQ ?= 16000000L
+atmega32u2atUART: $(PROGRAM)_atmega32u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega32u2atUART: $(PROGRAM)_atmega32u2_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega32u2:
+	"$(MAKE)" atmega32u2atUART UART?=1
+
+atmega32u2_isp: atmega32u2
+atmega32u2_isp: TARGET = atmega32u2
+atmega32u2_isp: MCU_TARGET = atmega32u2
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega32u2_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega32u2_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega32u2_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega32u2_isp: EFUSE ?= FE# = 2.7V brownout
+atmega32u2_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega32u2_isp: isp
+
+
+#-----------------------
+# ATmega 16u4
+#-----------------------
+#ATmega16u4
+atmega16u4atUART: TARGET = atmega16u4
+atmega16u4atUART: MCU_TARGET = atmega16u4
+atmega16u4atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega16u4atUART: AVR_FREQ ?= 16000000L
+atmega16u4atUART: $(PROGRAM)_atmega16u4_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega16u4atUART: $(PROGRAM)_atmega16u4_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega16u4:
+# disable blinking the LED to make the bootloader to fit in 512 Bytes Bootsection
+	"$(MAKE)" atmega16u4atUART UART?=1 LED_START_FLASHES?=0
+
+atmega16u4_isp: atmega16u4
+atmega16u4_isp: TARGET = atmega16u4
+atmega16u4_isp: MCU_TARGET = atmega16u4
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega16u4_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega16u4_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega16u4_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega16u4_isp: EFUSE ?= FB# = 2.6V brownout
+atmega16u4_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega16u4_isp: isp
+
+
+#-----------------------
+# ATmega 32u4
+#-----------------------
+#ATmega32u4
+atmega32u4atUART: TARGET = atmega32u4
+atmega32u4atUART: MCU_TARGET = atmega32u4
+atmega32u4atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega32u4atUART: AVR_FREQ ?= 16000000L
+atmega32u4atUART: $(PROGRAM)_atmega32u4_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega32u4atUART: $(PROGRAM)_atmega32u4_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega32u4:
+# disable blinking the LED to make the bootloader to fit in 512 Bytes Bootsection
+	"$(MAKE)" atmega32u4atUART UART?=1 LED_START_FLASHES?=0
+
+atmega32u4_isp: atmega32u4
+atmega32u4_isp: TARGET = atmega32u4
+atmega32u4_isp: MCU_TARGET = atmega32u4
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega32u4_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega32u4_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega32u4_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega32u4_isp: EFUSE ?= FB# = 2.6V brownout
+atmega32u4_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega32u4_isp: isp
+
+
+#-----------------------
+# ATmega 32u6
+#-----------------------
+#ATmega32u6
+atmega32u6atUART: TARGET = atmega32u6
+atmega32u6atUART: MCU_TARGET = atmega32u6
+atmega32u6atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+atmega32u6atUART: AVR_FREQ ?= 16000000L
+atmega32u6atUART: $(PROGRAM)_atmega32u6_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+atmega32u6atUART: $(PROGRAM)_atmega32u6_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+atmega32u6:
+	"$(MAKE)" atmega32u6atUART UART?=1
+
+atmega32u6_isp: atmega32u6
+atmega32u6_isp: TARGET = atmega32u6
+atmega32u6_isp: MCU_TARGET = atmega32u6	
+ifndef BIGBOOT ## standard version is 512 Bytes long; starts earlier
+atmega32u6_isp: HFUSE ?= DE# = 512 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+else ## bigboot version is 1024 Bytes long; starts earlier
+atmega32u6_isp: HFUSE ?= DC# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+endif
+atmega32u6_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+atmega32u6_isp: EFUSE ?= FB# = 2.6V brownout
+atmega32u6_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+atmega32u6_isp: isp
+
+
+#-----------------------
+# AT90USB646
+#-----------------------
+#at90usb646
+at90usb646atUART: TARGET = at90usb646
+at90usb646atUART: MCU_TARGET = at90usb646
+at90usb646atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+at90usb646atUART: AVR_FREQ ?= 16000000L
+at90usb646atUART: $(PROGRAM)_at90usb646_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+at90usb646atUART: $(PROGRAM)_at90usb646_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+at90usb646:
+	"$(MAKE)" at90usb646atUART UART?=1 BIGBOOT?=1
+
+at90usb646_isp: at90usb646
+at90usb646_isp: TARGET = at90usb646
+at90usb646_isp: MCU_TARGET = at90usb646
+at90usb646_isp: HFUSE ?= DE# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+at90usb646_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+at90usb646_isp: EFUSE ?= FB# = 2.6V brownout
+at90usb646_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+at90usb646_isp: isp
+
+
+#-----------------------
+# AT90USB647
+#-----------------------
+#at90usb647
+at90usb647atUART: TARGET = at90usb647
+at90usb647atUART: MCU_TARGET = at90usb647
+at90usb647atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+at90usb647atUART: AVR_FREQ ?= 16000000L
+at90usb647atUART: $(PROGRAM)_at90usb647_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+at90usb647atUART: $(PROGRAM)_at90usb647_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+at90usb647:
+	"$(MAKE)" at90usb647atUART UART?=1 BIGBOOT?=1
+
+at90usb647_isp: at90usb647
+at90usb647_isp: TARGET = at90usb647
+at90usb647_isp: MCU_TARGET = at90usb647	
+at90usb647_isp: HFUSE ?= DE# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+at90usb647_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+at90usb647_isp: EFUSE ?= FB# = 2.6V brownout
+at90usb647_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+at90usb647_isp: isp
+
+
+#-----------------------
+# AT90USB1286
+#-----------------------
+#at90usb1286
+at90usb1286atUART: TARGET = at90usb1286
+at90usb1286atUART: MCU_TARGET = at90usb1286
+at90usb1286atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+at90usb1286atUART: AVR_FREQ ?= 16000000L
+at90usb1286atUART: $(PROGRAM)_at90usb1286_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+at90usb1286atUART: $(PROGRAM)_at90usb1286_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+at90usb1286:
+	"$(MAKE)" at90usb1286atUART UART?=1 BIGBOOT?=1
+
+at90usb1286_isp: at90usb1286
+at90usb1286_isp: TARGET = at90usb1286
+at90usb1286_isp: MCU_TARGET = at90usb1286	
+at90usb1286_isp: HFUSE ?= DE# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+at90usb1286_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+at90usb1286_isp: EFUSE ?= FB# = 2.6V brownout
+at90usb1286_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+at90usb1286_isp: isp
+
+
+#-----------------------
+# AT90USB1287
+#-----------------------
+#at90usb1287
+at90usb1287atUART: TARGET = at90usb1287
+at90usb1287atUART: MCU_TARGET = at90usb1287
+at90usb1287atUART: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD)
+at90usb1287atUART: AVR_FREQ ?= 16000000L
+at90usb1287atUART: $(PROGRAM)_at90usb1287_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).hex
+ifndef PRODUCTION
+at90usb1287atUART: $(PROGRAM)_at90usb1287_UART$(UART)_$(BAUD_RATE)_$(AVR_FREQ)_BB$(BIGBOOT).lst
+endif
+at90usb1287:
+	"$(MAKE)" at90usb1287atUART UART?=1 BIGBOOT?=1 BIGBOOT?=1
+
+at90usb1287_isp: at90usb1287
+at90usb1287_isp: TARGET = at90usb1287
+at90usb1287_isp: MCU_TARGET = at90usb1287	
+at90usb1287_isp: HFUSE ?= DE# = 1024 byte boot, SPI (ISP!!!) enabled, JTAG disabled
+at90usb1287_isp: LFUSE ?= FF# = Full Swing xtal (16MHz) 16KCK/14CK+65ms
+at90usb1287_isp: EFUSE ?= FB# = 2.6V brownout
+at90usb1287_isp: LOCK  ?= 2F# = APP protect mode 1, BL protect mode 2
+at90usb1287_isp: isp
+

+ 99 - 0
optiboot/README.TXT

@@ -0,0 +1,99 @@
+This directory contains the Optiboot small bootloader for AVR
+microcontrollers, somewhat modified specifically for the Arduino
+environment.
+
+Optiboot is more fully described here: http://github.com/Optiboot/optiboot
+and is the work of Peter Knight (aka Cathedrow), building on work of Jason P
+Kyle, Spiff, and Ladyada.  More recent maintenance and modifications are by
+Bill Westfield (aka WestfW)
+
+Arduino-specific issues are tracked as part of the Arduino project
+at http://github.com/arduino/Arduino
+
+
+Most of the information in this file is superceeded by the wiki content at
+https://github.com/Optiboot/optiboot/wiki
+
+It's till here "just in case."
+
+------------------------------------------------------------
+
+Building optiboot for Arduino.
+
+Production builds of optiboot for Arduino are done on a Mac in "unix mode"
+using CrossPack-AVR-20100115.  CrossPack tracks WINAVR (for windows), which
+is just a package of avr-gcc and related utilities, so similar builds should
+work on Windows or Linux systems.
+
+One of the Arduino-specific changes is modifications to the makefile to
+allow building optiboot using only the tools installed as part of the
+Arduino environment, or the Arduino source development tree.  All three
+build procedures should yield identical binaries (.hex files) (although
+this may change if compiler versions drift apart between CrossPack and
+the Arduino IDE.)
+
+
+Building Optiboot in the Arduino IDE Install.
+
+Work in the .../hardware/arduino/bootloaders/optiboot/ and use the
+"omake <targets>" command, which just generates a command that uses
+the arduino-included "make" utility with a command like:
+    make OS=windows ENV=arduino <targets>
+or  make OS=macosx ENV=arduino <targets>
+On windows, this assumes you're using the windows command shell.  If
+you're using a cygwin or mingw shell, or have one of those in your
+path, the build will probably break due to slash vs backslash issues.
+On a Mac, if you have the developer tools installed, you can use the
+Apple-supplied version of make.
+The makefile uses relative paths ("../../../tools/" and such) to find
+the programs it needs, so you need to work in the existing optiboot
+directory (or something created at the same "level") for it to work.
+
+
+Building Optiboot in the Arduino Source Development Install.
+
+In this case, there is no special shell script, and you're assumed to
+have "make" installed somewhere in your path.
+Build the Arduino source ("ant build") to unpack the tools into the
+expected directory.
+Work in Arduino/hardware/arduino/bootloaders/optiboot and use
+    make OS=windows ENV=arduinodev <targets>
+or  make OS=macosx ENV=arduinodev <targets>
+
+
+Programming Chips Using the _isp Targets
+
+The CPU targets have corresponding ISP targets that will actuall
+program the bootloader into a chip. "atmega328_isp" for the atmega328,
+for example.  These will set the fuses and lock bits as appropriate as
+well as uploading the bootloader code.
+
+ISP Targets in Version 5.0 and later:
+
+The isp targets are now built using a separate "Makefile.isp" makefile,
+which should make modification easier and more obvious.  This also fixes
+the atmega8_isp target problem mentioned below.  The default
+configuration assumes an ArduinoISP setup, but you will probably need to
+update at least the serial port, since those are different for each
+Arduino board and/or system/
+
+
+ISP Targets in Version 4.6 and earlier:
+
+The older makefiles default to using a USB programmer, but you can use a
+serial programmer like ArduinoISP by changing the appropriate variables
+when you invoke make:
+
+   make ISPTOOL=stk500v1 ISPPORT=/dev/tty.usbserial-A20e1eAN  \
+        ISPSPEED=-b19200 atmega328_isp
+
+The "atmega8_isp" target does not currently work, because the mega8
+doesn't have the "extended" fuse that the generic ISP target wants to
+pass on to avrdude.  You'll need to run avrdude manually.
+
+
+Standard Targets
+
+I've reduced the pre-built and source-version-controlled targets
+(.hex and .lst files included in the git repository) to just the
+three basic 16MHz targets: atmega8, atmega16, atmega328.

+ 64 - 0
optiboot/baudcheck.c

@@ -0,0 +1,64 @@
+/*
+ * baudcheck.c
+ * Mar, 2013 by Bill Westfield (WestfW@yahoo.com)
+ * Exercises in executing arithmetic code on a system that we can't count
+ * on having the usual languages or tools installed.
+ *
+ * This little "C program" is run through the C preprocessor using the same
+ * arguments as our "real" target (which should assure that it gets the
+ * same values for clock speed and desired baud rate), and produces as
+ * output a shell script that can be run through bash, and THAT in turn
+ * writes the desired output...
+ *
+ * Note that the C-style comments are stripped by the C preprocessor.
+ *
+ * Copyright 2013-2015 by Bill Westfield.
+ * This software is licensed under version 2 of the Gnu Public Licence.
+ * See optiboot.c for details.
+ */
+
+/*
+ * First strip any trailing "L" from the defined constants.  To do this
+ * we need to make the constants into shell variables first.
+ */
+bpsx=BAUD_RATE
+bps=${bpsx/L/}
+bps=${bps/U/}
+fcpux=F_CPU
+fcpu=${fcpux/L/}
+fcpu=${fcpu/U/}
+
+// echo f_cpu = $fcpu, baud = $bps
+/*
+ * Compute the divisor
+ */
+#ifdef SINGLESPEED
+BAUD_SETTING=$(( ( ($fcpu + $bps * 8) / (($bps * 16))) - 1 ))
+#else
+BAUD_SETTING=$(( ( ($fcpu + $bps * 4) / (($bps * 8))) - 1 ))
+#endif
+// echo baud setting = $BAUD_SETTING
+
+/*
+ * Based on the computer divisor, calculate the actual bitrate,
+ * And the error.  Since we're all integers, we have to calculate
+ * the tenths part of the error separately.
+ */
+#ifdef SINGLESPEED
+BAUD_ACTUAL=$(( ($fcpu/(16 * (($BAUD_SETTING)+1))) ))
+#else
+BAUD_ACTUAL=$(( ($fcpu/(8 * (($BAUD_SETTING)+1))) ))
+#endif
+BAUD_ERROR=$(( (( 100*($BAUD_ACTUAL - $bps) ) / $bps) ))
+ERR_TS=$(( ((( 1000*($BAUD_ACTUAL - $bps) ) / $bps) - $BAUD_ERROR * 10) ))
+ERR_TENTHS=$(( ERR_TS > 0 ? ERR_TS: -ERR_TS ))
+
+/*
+ * Print a nice message containing the info we've calculated
+ */
+echo BAUD RATE CHECK: Desired: $bps,  Real: $BAUD_ACTUAL, UBRRL = $BAUD_SETTING, Difference=$BAUD_ERROR.$ERR_TENTHS\%
+
+
+
+
+

+ 101 - 0
optiboot/boot_opt.h

@@ -0,0 +1,101 @@
+// Get all the "standard" definitions from the official boot.h
+#include <avr/boot.h>
+
+
+/*
+ * Implement some optimized versions that will use OUT instead
+ *   of STS to write SPMCSR.
+ *   (However, omit the *_extended_short, since by the time you
+ *   need _extended_, the extra byte shouldn't be relevant any more)
+ *
+ * The C preprocessor can not determin at compile time whether SPMCSR is
+ *   "out of range" of the OUT instruction, but we CAN do that in the
+ *   assembler.  We can even make it pretty with a macro.
+ * With this modification, the _short functions should work on cpus
+ *   (like ATmega128) where STS is required.
+ */
+
+asm(".macro __wr_spmcsr p, v \n\t"
+    ".if \\p > 0x57	\n\t"
+    "sts \\p, \\v	\n\t"
+    ".else		\n\t"
+    "out \\p-0x20, \\v	\n\t"
+    ".endif		\n\t"
+    ".endm		\n");
+
+
+#if defined(__SPM_REG)
+
+#define __boot_page_fill_short(address, data)    \
+(__extension__({                                 \
+    __asm__ __volatile__                         \
+    (                                            \
+        "movw  r0, %3\n\t"                       \
+        "__wr_spmcsr %0, %1\n\t"                 \
+        "spm\n\t"                                \
+        "clr  r1\n\t"                            \
+        :                                        \
+        : "i" (_SFR_MEM_ADDR(__SPM_REG)),         \
+          "r" ((uint8_t)__BOOT_PAGE_FILL),       \
+          "z" ((uint16_t)address),               \
+          "r" ((uint16_t)data)                   \
+        : "r0"                                   \
+    );                                           \
+}))
+
+#define __boot_page_erase_short(address)         \
+(__extension__({                                 \
+    __asm__ __volatile__                         \
+    (                                            \
+        "__wr_spmcsr %0, %1\n\t"                 \
+        "spm\n\t"                                \
+        :                                        \
+        : "i" (_SFR_MEM_ADDR(__SPM_REG)),         \
+          "r" ((uint8_t)__BOOT_PAGE_ERASE),      \
+          "z" ((uint16_t)address)                \
+    );                                           \
+}))
+
+#define __boot_page_write_short(address)         \
+(__extension__({                                 \
+    __asm__ __volatile__                         \
+    (                                            \
+        "__wr_spmcsr %0, %1\n\t"                 \
+        "spm\n\t"                                \
+        :                                        \
+        : "i" (_SFR_MEM_ADDR(__SPM_REG)),         \
+          "r" ((uint8_t)__BOOT_PAGE_WRITE),      \
+          "z" ((uint16_t)address)                \
+    );                                           \
+}))
+
+#define __boot_rww_enable_short()                \
+(__extension__({                                 \
+    __asm__ __volatile__                         \
+    (                                            \
+        "__wr_spmcsr %0, %1\n\t"                 \
+        "spm\n\t"                                \
+        :                                        \
+        : "i" (_SFR_MEM_ADDR(__SPM_REG)),         \
+          "r" ((uint8_t)__BOOT_RWW_ENABLE)       \
+    );                                           \
+}))
+
+#endif // __SPM_REG
+
+#ifndef __boot_page_erase_short
+
+/*
+ * if __SPM_REG didn't get defined by now, but we didn't exit it means
+ * we have some sort of new-fangled chip that post-dates the version
+ * of boot.h that we know about.  In this case, it's possible that the
+ * standard boot.h still has workable functions, so we'll alias those.
+ */
+
+#define __boot_page_fill_short(address, data) boot_page_fill(address, data)
+#define __boot_page_erase_short(address) boot_page_erase(address)
+#define __boot_page_write_short(address) boot_page_write(address)
+#define __boot_rww_enable_short() boot_rww_enable()
+
+#endif
+

+ 145 - 0
optiboot/link_optiboot.ld

@@ -0,0 +1,145 @@
+/* Customized Linker script for Optiboot */
+
+/* Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2021 by William Westfield
+   Copying and distribution of this script, with or without modification,
+   are permitted in any medium without royalty provided the copyright
+   notice and this notice are preserved.
+*/
+
+/*
+ * this is based off of the default ATmega328 linker script, but it
+ * has been generalized (since optiboot makes little use of the standard
+ * chip-specific values), and also specialized to based start addresses
+ * of the code on symbols passed from the C program, instead of needing
+ * --section-start commands in the linker command line.
+ * (The C program does this by using asm() statements to define absolute
+ * symbols that the linker can see.
+ * The .data and .bss segments are removed, since the bootloader must not
+ * use them (and does its own memory management) (this has the added
+ * "benefit" of spitting out error messages if the code DOES try to
+ * use data or bss variables.
+ */
+
+OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr")
+__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
+/* This makes the disassembly listings prettier */
+__RAM__ = 0x800000;
+
+MEMORY
+{
+  text   (rx)   : ORIGIN = __BOOT_START__, LENGTH = __BOOT_SIZE__
+  version   (rx)   : ORIGIN = __VERSION_START__, LENGTH = 2
+  fuse      (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
+}
+
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  /* Internal text space or external memory.  */
+  .text   :
+  {
+    *(.vectors)
+    KEEP(*(.vectors))
+    /* For data that needs to reside in the lower 64k of progmem.  */
+     *(.progmem.gcc*)
+    /* PR 13812: Placing the trampolines here gives a better chance
+       that they will be in range of the code that uses them.  */
+    . = ALIGN(2);
+    *(.init0)  /* Start here after reset.  */
+    KEEP (*(.init0))
+    *(.init1)
+    KEEP (*(.init1))
+    *(.init2)  /* Clear __zero_reg__, set up stack pointer.  */
+    KEEP (*(.init2))
+    *(.init3)
+    KEEP (*(.init3))
+    *(.init4)  /* Initialize data and BSS.  */
+    KEEP (*(.init4))
+    *(.init5)
+    KEEP (*(.init5))
+    *(.init6)  /* C++ constructors.  */
+    KEEP (*(.init6))
+    *(.init7)
+    KEEP (*(.init7))
+    *(.init8)
+    KEEP (*(.init8))
+    *(.init9)  /* Call main().  */
+    KEEP (*(.init9))
+    *(.text)
+    . = ALIGN(2);
+     *(.text.*)
+    . = ALIGN(2);
+    *(.fini9)  /* _exit() starts here.  */
+    KEEP (*(.fini9))
+    *(.fini8)
+    KEEP (*(.fini8))
+    *(.fini7)
+    KEEP (*(.fini7))
+    *(.fini6)  /* C++ destructors.  */
+    KEEP (*(.fini6))
+    *(.fini5)
+    KEEP (*(.fini5))
+    *(.fini4)
+    KEEP (*(.fini4))
+    *(.fini3)
+    KEEP (*(.fini3))
+    *(.fini2)
+    KEEP (*(.fini2))
+    *(.fini1)
+    KEEP (*(.fini1))
+    *(.fini0)  /* Infinite loop after program termination.  */
+    KEEP (*(.fini0))
+     _etext = . ;
+  }  > text
+  .version __VERSION_START__ :
+  {
+    *(.version)
+  } > text
+  .fuse  :
+  {
+    KEEP(*(.fuse))
+    KEEP(*(.lfuse))
+    KEEP(*(.hfuse))
+    KEEP(*(.efuse))
+  }  > fuse
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  /* DWARF Extension.  */
+  .debug_macro    0 : { *(.debug_macro) }
+}

+ 34 - 0
optiboot/make-ccversions

@@ -0,0 +1,34 @@
+#
+# Compile a couple of Optiboot variations using several different compilers
+#
+
+
+# A list of compilers that are available.
+#   This is, um, 4.3.3, 4.6.2, 4.8.1, 4.9.2, and 5.4.0
+#
+COMPS='
+/usr/local/CrossPack-AVR-20100115/bin/
+/usr/local/CrossPack-AVR-20121207/bin/
+/usr/local/CrossPack-AVR-48/bin/
+/usr/local/avr8-atmel-20160624/bin/
+/usr/local/avr8-Atmel-3.6.0.487/bin/
+'
+
+for c in $COMPS; do
+  #  Pretty print for readability
+  echo
+  echo
+  echo ===========================================================
+  echo Using compiler in $c
+  $c/avr-gcc --version | head -1
+  echo ===========================================================
+
+  echo ---------------  make GCCROOT=$c atmega328
+  make GCCROOT=$c atmega328
+  echo ---------------  make GCCROOT=$c atmega1284
+  make GCCROOT=$c atmega1284 
+  echo ---------------  make GCCROOT=$c luminet
+  make GCCROOT=$c luminet
+  echo ---------------  make GCCROOT=$c mega1280
+  make GCCROOT=$c mega1280
+done

+ 1692 - 0
optiboot/optiboot.c

@@ -0,0 +1,1692 @@
+#define FUNC_READ 1
+#define FUNC_WRITE 1
+/**********************************************************/
+/* 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 environment 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         */
+/*   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                             */
+/*                                                        */
+/* Supported Devices:                                     */
+/*   With the merges of Spence Konde's ATTinyCore         */
+/*     https://github.com/SpenceKonde/ATTinyCore          */
+/*   and MCUDude's MightyCore, MiniCore, MegaCore, etc    */
+/*     https://github.com/MCUdude                         */
+/*   the number of supported chips and configurations     */
+/*   has become quite large.  Try "make help" for a list  */
+/*   Not all chips have received the same amount of       */
+/*   overall attention.  Some version may have bugs.      */
+/*                                                        */
+/* 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         */
+/*                                                        */
+
+/* Copyright 2013-2021 by Bill Westfield.                 */
+/* Copyright 2010 by Peter Knight.                        */
+/*  Note that many others have made major contributions!  */
+/*                                                        */
+/* 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.gnu.org/licenses/old-licenses/gpl-2.0.txt   */
+/*                                                        */
+/**********************************************************/
+
+
+/**********************************************************/
+/*                                                        */
+/* Optional defines:                                      */
+/*                                                        */
+/**********************************************************/
+/*                                                        */
+/* BIGBOOT:                                               */
+/* Build a 1k bootloader, not 512 bytes. This turns on    */
+/* extra functionality; notably EEPROM                    */
+/*                                                        */
+/* NO_APP_SPM:                                            */
+/* omit the code that allows applications to "call" the   */
+/* bootloader to perform SPM operations.                  */
+/*                                                        */
+/* SUPPORT_EEPROM:                                        */
+/* Support reading and writing from EEPROM. This is not   */
+/* used by Arduino, so off by default.                    */
+/*                                                        */
+/* WDTTIME:                                               */
+/* Bootloader timeout period, in seconds.                 */
+/*  1 and 2 seconds are available on all chips            */
+/*  4 and 8 are supported on most                         */
+/*                                                        */
+/* NO_START_APP_ON_POR:                                   */
+/* If NO_START_APP_ON_POR is set, the bootloader will     */
+/* also run on power-on                                   */
+/*                                                        */
+/* START_APP_ON_EXTR:                                     */
+/* If START_APP_ON_EXTR is set, the bootloader will not   */
+/* run in the event of an external reset.                 */
+/*                                                        */
+/* If both are set, the bootloader will only run if the   */
+/* app jumps directly to it.                              */
+/*                                                        */
+/* ----------  Comm features                              */
+/* UART:                                                  */
+/* UART number (0..n) for devices with more than          */
+/* one hardware uart (644P, 1284P, etc)                   */
+/*                                                        */
+/* BAUD_RATE:                                             */
+/* Set bootloader baud rate.                              */
+/*                                                        */
+/* SINGLESPEED:                                           */
+/* do not use "U2X" mode for UART initialization. This    */
+/* can be useful for some bit rates.                      */
+/*                                                        */
+/* SOFT_UART:                                             */
+/* Use AVR305 soft-UART instead of hardware UART.         */
+/*                                                        */
+/* RS485:                                                 */
+/* Either a pin (ex: "B5") or a pin followed by _INV      */
+/* (ex: "B5_INV") which indicates inverted polarity.      */
+/* This pin will be held low while transmitting in order  */
+/* to control the direction pin of an RS485 tranciever    */
+/*  (RS485 support by Vladimir Dronnikov (github.com/dvv) */
+/*    as used in github.com/SodaqMoja/optiboot )          */
+/*                                                        */
+/* ----------  LED behavior                               */
+/* LED:                                                   */
+/* Which pin to use for the LED flashs.  This is a pin    */
+/* name like "B5"                                         */
+/*                                                        */
+/* 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.   */
+/*                                                        */
+/* LED_START_ON:                                          */
+/* Instead of blinking, turn the LED on when we start,    */
+/* and off when it exits.  Slightly smaller code.         */
+/*                                                        */
+/**********************************************************/
+
+/*
+ * default values.
+ */
+#if !defined(BIGBOOT)
+#  define BIGBOOT 0
+#endif
+#if !defined(SUPPORT_EEPROM)
+#  define SUPPORT_EEPROM 0
+#endif
+#if !defined(APP_NOSPM)
+#  define APP_NOSPM 0
+#endif
+#if !defined(START_APP_ON_EXTR)
+#  define START_APP_ON_EXTR 0
+#endif
+#if !defined(NO_START_APP_ON_POR)
+#  define NO_START_APP_ON_POR 0
+#endif
+
+
+/* UART options */
+#if !defined(SOFT_UART)
+#  define SOFT_UART 0
+#endif
+#if !defined(UART)
+#define UART 0
+#endif
+#if !defined(SINGLESPEED)
+#define SINGLESPEED 0
+#endif
+
+/* LED Options */
+#if !defined(LED_START_FLASHES)
+#define LED_START_FLASHES 0
+#endif
+#if !defined(LED_DATA_FLASH)
+#  define LED_DATA_FLASH 0
+#endif
+#if !defined(LED_START_ON)
+#  define LED_START_ON 0
+#endif
+
+
+/**********************************************************/
+/* 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*/
+/* Version 6 added EEPROM support, including causing an   */
+/*  error when trying to write eeprom with versions that  */
+/*  didn't have the code there. Makefiles were further    */
+/*  restructured.  Overlapping SPM/download removed.      */
+/* Version 7 straightened out the MCUSR and RESET         */
+/*  handling, did MORE Makefile mods.  EEPROM support now */
+/*  fits in 512 bytes, if you turn off LED Blinking.      */
+/*  Various bigboot and virboot targets were fixed.       */
+/* Version 8.0 adds the do_spm code callable from Apps.   */
+/*                                                        */
+/* 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.  The CUSTOM_VERSION=n option      */
+/*  adds n to the high version to facilitate this.        */
+/*                                                        */
+/**********************************************************/
+
+/**********************************************************/
+/* Edit History:                                          */
+/*                                                        */
+/* Oct 2021                                               */
+/* 8.3 WestfW add section-start determination code to     */
+/*     the C source.  In theory, this causes no changes   */
+/*     to the binary, but it's "risky", so ... bump.      */
+/* Aug 2019                                               */
+/* 8.1  WestfW Fix bug in calculation of Vboot offset     */
+/* Sep 2018                                               */
+/* 8.0  WestfW (and Majekw and MCUDude)                   */
+/*      Include do_spm routine callable from the app      */
+/*      at BOOTSTART+2, controllable with compile option  */
+/* July 2018                                              */
+/* 7.0  WestfW (with much input from Others)              */
+/*      Fix MCUSR treatement as per much discussion,      */
+/*       Patches by MarkG55, majekw.  Preserve value      */
+/*       for the application, as much as possible.        */
+/*       see https://github.com/Optiboot/optiboot/issues/97 */
+/*      Optimize a bit by implementing a union for the    */
+/*       various 16bit address values used (based on      */
+/*       observation by "aweatherguy", but different.)    */
+/*      Slightly optimize math in VIRTUAL_BOOT code       */
+/*      Add some virboot targets, fix some fuses.         */
+/*      Implement LED_START_ON; less code than flashes    */
+/* Aug 2014                                               */
+/* 6.2 WestfW: make size of length variables dependent    */
+/*              on the SPM_PAGESIZE.  This saves space    */
+/*              on the chips where it's most important.   */
+/* 6.1 WestfW: Fix OPTIBOOT_CUSTOMVER (send it!)          */
+/*             Make no-wait mod less picky about          */
+/*               skipping the bootloader.                 */
+/*             Remove some dead code                      */
+/* Jun 2014                                               */
+/* 6.0 WestfW: Modularize memory read/write functions     */
+/*             Remove serial/flash overlap                */
+/*              (and all references to NRWWSTART/etc)     */
+/*             Correctly handle pagesize > 255bytes       */
+/*             Add EEPROM support in BIGBOOT (1284)       */
+/*             EEPROM write on small chips now causes err */
+/*             Split Makefile into smaller pieces         */
+/*             Add Wicked devices Wildfire                */
+/*             Move UART=n conditionals into pin_defs.h   */
+/*             Remove LUDICOUS_SPEED option               */
+/*             Replace inline assembler for .version      */
+/*              and add OPTIBOOT_CUSTOMVER for user code  */
+/*             Fix LED value for Bobuino (Makefile)       */
+/*             Make all functions explicitly inline or    */
+/*              noinline, so we fit when using gcc4.8     */
+/*             Change optimization options for gcc4.8     */
+/*             Make ENV=arduino work in 1.5.x trees.      */
+/* May 2014                                               */
+/* 5.0 WestfW: Add support for 1Mbps UART                 */
+/* 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 OPTIBOOT_MAJVER 8
+#define OPTIBOOT_MINVER 3
+
+/*
+ * OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
+ * of optiboot.  That way you don't wind up with very different code that
+ * matches the version number of a "released" optiboot.
+ */
+
+#if !defined(OPTIBOOT_CUSTOMVER)
+#define OPTIBOOT_CUSTOMVER 0
+#endif
+
+unsigned const int __attribute__((section(".version")))
+optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER;
+
+
+#define __AVR_LIBC_DEPRECATED_ENABLE__ 1  // don't poison MCUSR on some chips
+#include <inttypes.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <avr/eeprom.h>
+
+/*
+ * optiboot uses several "address" variables that are sometimes byte pointers,
+ * sometimes word pointers. sometimes 16bit quantities, and sometimes built
+ * up from 8bit input characters.  avr-gcc is not great at optimizing the
+ * assembly of larger words from bytes, but we can use the usual union to
+ * do this manually.  Expanding it a little, we can also get rid of casts.
+ */
+typedef union {
+  uint8_t  *bptr;
+  uint16_t *wptr;
+  uint16_t word;
+  uint8_t bytes[2];
+} addr16_t;
+
+/*
+ * Note that we use a replacement of "boot.h"
+ * <avr/boot.h> uses sts instructions, but this version uses out instructions
+ * This saves cycles and program memory, if possible.
+ * boot_opt.h pulls in the standard boot.h for the odd target (?)
+ */
+#include "boot_opt.h"
+
+
+// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
+
+/*
+ * pin_defs.h
+ * This contains most of the rather ugly defines that implement our
+ * ability to use UART=n and LED=D3, and some avr family bit name differences.
+ */
+#include "pin_defs.h"
+
+/*
+ * stk500.h contains the constant definitions for the stk500v1 comm protocol
+ */
+#include "stk500.h"
+
+/* set the UART baud rate defaults */
+#ifndef BAUD_RATE
+#if F_CPU >= 8000000L
+#define BAUD_RATE   115200L // Highest rate Avrdude win32 will support
+#elif F_CPU >= 1000000L
+#define BAUD_RATE   9600L   // 19200 also supported, but with significant error
+#elif F_CPU >= 128000L
+#define BAUD_RATE   4800L   // Good for 128kHz internal RC
+#else
+#define BAUD_RATE 1200L     // Good even at 32768Hz
+#endif
+#endif
+
+#if (SOFT_UART == 0)
+#if SINGLESPEED
+/* Single speed option */
+#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 8L) / ((BAUD_RATE * 16L))) - 1 )
+#define BAUD_ACTUAL (F_CPU/(16 * ((BAUD_SETTING)+1)))
+#else
+/* Normal U2X usage */
+#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 )
+#define BAUD_ACTUAL (F_CPU/(8 * ((BAUD_SETTING)+1)))
+#endif
+#if BAUD_ACTUAL <= BAUD_RATE
+#define BAUD_ERROR (( 100*(BAUD_RATE - BAUD_ACTUAL) ) / BAUD_RATE)
+#if BAUD_ERROR >= 5
+#error BAUD_RATE off by greater than -5%
+#elif BAUD_ERROR >= 2  && !defined(PRODUCTION)
+#warning BAUD_RATE off by greater than -2%
+#endif
+#else
+#define BAUD_ERROR (( 100*(BAUD_ACTUAL - BAUD_RATE) ) / BAUD_RATE)
+#if BAUD_ERROR >= 5
+#error BAUD_RATE off by greater than 5%
+#elif BAUD_ERROR >= 2  && !defined(PRODUCTION)
+#warning BAUD_RATE off by greater than 2%
+#endif
+#endif
+
+#if BAUD_SETTING > 250
+#error Unachievable baud rate (too slow) BAUD_RATE
+#endif // baud rate slow check
+#if (BAUD_SETTING - 1) < 3
+#if BAUD_ERROR != 0 // permit high bitrates (ie 1Mbps@16MHz) if error is zero
+#error Unachievable baud rate (too fast) BAUD_RATE
+#endif
+#endif // baud rate fast check
+#endif // SOFT_UART
+
+/* 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))
+#ifdef  WDP3
+#define WATCHDOG_4S     (_BV(WDP3) | _BV(WDE))
+#define WATCHDOG_8S     (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
+#endif
+
+  /*
+   * Watchdog timeout translations from human readable to config vals
+   */
+#ifndef WDTTIME
+# define WDTPERIOD WATCHDOG_1S  // 1 second default
+#elif WDTTIME == 1
+# define WDTPERIOD WATCHDOG_1S  // 1 second
+#elif WDTTIME == 2
+# define WDTPERIOD WATCHDOG_2S  // 2 seconds
+#elif defined(WDP3) && (WDTTIME == 4)
+# define WDTPERIOD WATCHDOG_4S  // 4 seconds
+#elif defined(WDP3) && (WDTTIME == 8)
+# define WDTPERIOD WATCHDOG_8S  // 8 seconds
+#else
+#error Invalid TIMEOUT
+#endif
+
+/*
+ * We can never load flash with more than 1 page at a time, so we can save
+ * some code space on parts with smaller pagesize by using a smaller int.
+ */
+#if SPM_PAGESIZE > 255
+typedef uint16_t pagelen_t ;
+#define GETLENGTH(len) len = getch()<<8; len |= getch()
+#else
+typedef uint8_t pagelen_t;
+#define GETLENGTH(len) (void) getch() /* skip high byte */; len = getch()
+#endif
+
+
+/* Function Prototypes
+ * The main() function is in init9, which removes the interrupt vector table
+ * we don't need. It is also 'OS_main', which means the compiler does not
+ * generate any entry or exit code itself (but unlike 'naked', it doesn't
+ * suppress some compile-time options we want.)
+ */
+
+void pre_main(void) __attribute__ ((naked)) __attribute__ ((section (".init8")));
+int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))) __attribute__((used));
+
+void __attribute__((noinline)) __attribute__((leaf)) putch(char);
+uint8_t __attribute__((noinline)) __attribute__((leaf)) getch(void) ;
+void __attribute__((noinline)) verifySpace();
+void __attribute__((noinline)) watchdogConfig(uint8_t x);
+
+static void getNch(uint8_t);
+#if LED_START_FLASHES > 0
+static inline void flash_led(uint8_t);
+#endif
+static inline void watchdogReset();
+static inline void writebuffer(int8_t memtype, addr16_t mybuff,
+                               addr16_t address, pagelen_t len);
+static inline void read_mem(uint8_t memtype,
+                            addr16_t, pagelen_t len);
+
+#if SOFT_UART
+void uartDelay() __attribute__ ((naked));
+#endif
+
+/*
+ * RAMSTART should be self-explanatory.  It's bigger on parts with a
+ * lot of peripheral registers.  Let 0x100 be the default
+ * Note that RAMSTART (for optiboot) need not be exactly at the start of RAM.
+ */
+#if !defined(RAMSTART)  // newer versions of gcc avr-libc define RAMSTART
+#define RAMSTART 0x100
+#if defined (__AVR_ATmega644P__)
+// correct for a bug in avr-libc
+#undef SIGNATURE_2
+#define SIGNATURE_2 0x0A
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+#undef RAMSTART
+#define RAMSTART (0x200)
+#endif
+#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 */
+static addr16_t buff = {(uint8_t *)(RAMSTART)};
+
+/* Virtual boot partition support */
+#ifdef VIRTUAL_BOOT_PARTITION
+
+// RAM locations to save vector info (temporarilly)
+#define rstVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+4))
+#define rstVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+5))
+#define saveVect0_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+6))
+#define saveVect1_sav (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+7))
+
+#define RSTVEC_ADDRESS 0  // flash address where vectors start.
+// Vector to save original reset jump:
+//   SPM Ready is least probably used, so it's default
+//   if not, use old way WDT_vect_num,
+//   or simply set custom save_vect_num in Makefile using vector name
+//   or even raw number.
+#if !defined (save_vect_num)
+#if defined (SPM_RDY_vect_num)
+#define save_vect_num (SPM_RDY_vect_num)
+#elif defined (SPM_READY_vect_num)
+#define save_vect_num (SPM_READY_vect_num)
+#elif defined (EE_RDY_vect_num)
+#define save_vect_num (EE_RDY_vect_num)
+#elif defined (EE_READY_vect_num)
+#define save_vect_num (EE_READY_vect_num)
+#elif defined (WDT_vect_num)
+#define save_vect_num (WDT_vect_num)
+#else
+#error "Can't find SPM or WDT interrupt vector for this CPU"
+#endif
+#endif //save_vect_num
+
+// check if it's on the same page (code assumes that)
+
+#if FLASHEND > 8192
+// AVRs with more than 8k of flash have 4-byte vectors, and use jmp.
+//  We save only 16 bits of address, so devices with more than 128KB
+//  may behave wrong for upper part of address space.
+#define rstVect0 2
+#define rstVect1 3
+#define saveVect0 (save_vect_num*4+2)
+#define saveVect1 (save_vect_num*4+3)
+#define appstart_vec (save_vect_num*2)
+
+// address of page that will have the saved vector
+#define SAVVEC_ADDRESS (SPM_PAGESIZE*(save_vect_num/(SPM_PAGESIZE/4)))
+
+#else
+
+// AVRs with up to 8k of flash have 2-byte vectors, and use rjmp.
+#define rstVect0 0
+#define rstVect1 1
+#define saveVect0 (save_vect_num*2)
+#define saveVect1 (save_vect_num*2+1)
+#define appstart_vec (save_vect_num)
+
+// address of page that will have the saved vector
+#define SAVVEC_ADDRESS (SPM_PAGESIZE*(save_vect_num/(SPM_PAGESIZE/2)))
+#endif
+
+#else
+
+#define appstart_vec (0)
+
+#endif // VIRTUAL_BOOT_PARTITION
+
+void sectionOpts() __attribute__((naked));
+void sectionOpts() {
+/*
+ * Mysterious Magic code to allow section-start addresses to be
+ * specifed by the C code (which, after all, has access to CPP symbols
+ * like FLASHEND, and can make a "safer" guess than putting manually
+ * determined constants in the Makefile.  This is dependent on a custom
+ * linker script that makes use of the __BOOT_ symbols that we define.
+ * Fortunately, that script can be used to link optiboot on any of its
+ * usual chips.
+ *
+ * with some judicious use of asm directives, we can define symbols
+ * that the linker will look at for positioning our segments (in
+ * combination with a custom linker script) based on the flash size
+ * defined via io.h, instead of requiring magic --section-start
+ * constants on the build line.
+ *
+ * This apparently needs to be inside a function in order to pass
+ * arguments to the asm command (even though the asm doesn't
+ * generate any code)  But we can make sure the function (which doesn't
+ * actually contain any code) doesn't actually end up in the binary.
+ */
+#if BIGBOOT
+  /*
+   * BIGBOOT images are easy, because they're much smaller than the
+   * flash size that they are defined to occupy (1k)
+   */
+  asm(" .global __BOOT_SIZE__, __BOOT_START__, __VERSION_START__\n"
+      " .equ __BOOT_SIZE__, 1024\n"
+      " .equ __BOOT_START__, (%0-1023)\n"
+      " .equ __VERSION_START__, (%0-1)\n"
+      ::"i"((uint32_t)FLASHEND));
+#else
+  /*
+   * non-BIGBOOT images try to fit in 512bytes, but don't quite fit
+   * on chips that don't have HW support for a boot section.  We try
+   * to guess how big the extra bits of code are, and then round up
+   * to the next larger flash page boundry (which can be nearly 4 pages
+   * away on chips with FOURPAGEERASE)
+   * These numbers are determined manually by building a reference
+   * implementation with various options and comparing sizes.
+   */
+# if VIRTUAL_BOOT_PARTITION
+/*  VIRTUAL_BOOT_PARTITION code is about 100 bytes */
+#   define VBSIZE 110
+# else
+#   define VBSIZE 0
+# endif
+# if LED_START_FLASHES==0
+/*  if LED_START_FLASHES is 0 (eg on 8pin chips), it saves some code */
+#   define LEDSIZE (-30)
+# else
+#   define LEDSIZE 0
+# endif
+# if SOFT_UART
+/*  But not having a hardware UART costs a bit */
+#   define SOFTUSIZE 16
+# else
+#   define SOFTUSIZE 0
+# endif
+
+# if FOURPAGEERASE
+/*  FOURPAGEERASE adds some code, and also affects how we round */
+#   define ERASESIZE 8
+#   define PAGSIZ_B (SPM_PAGESIZE*4)
+# else
+#   define PAGSIZ_B (SPM_PAGESIZE)
+#   define ERASESIZE 0
+# endif
+
+/*
+ * Round our guess up to next page size.  So 560 byte images occupy 576bytes,
+ * 600 byte images occupy 640 bytes, etc.  Depending on chip.
+ * Note that SPM_PAGESIZE is already in bytes in the .h files.
+ */  
+# define ROUNDTOPAGE(size) (((size + (PAGSIZ_B/2))/(PAGSIZ_B))*(PAGSIZ_B))
+/* use 511 here so we don't round up to the next page on normal systems. */
+# define BOOTSIZE (511+ERASESIZE+VBSIZE+SOFTUSIZE+LEDSIZE)
+  asm(" .global __BOOT_SIZE__, __BOOT_START__, __VERSION_START__\n"
+      " .equ __BOOT_SIZE__, %1\n"
+      " .equ __BOOT_START__, ((%0+1)-%1)\n"
+      " .equ __VERSION_START__, (%0-1)\n"
+      ::"i"((uint32_t)FLASHEND), "i"(ROUNDTOPAGE(BOOTSIZE)));
+#endif
+/* Wasn't that FUN! */
+}
+
+/* everything that needs to run VERY early */
+void pre_main(void) {
+  // Allow convenient way of calling do_spm function - jump table, so
+  //   entry to this function will always be here, independent of
+  //   compilation, features etc
+  asm volatile (
+    "  rjmp    1f\n"
+#if APP_NOSPM
+    "  ret\n"   // if do_spm isn't include, return without doing anything
+#else
+    "  rjmp    do_spm\n"
+#endif
+    "1:\n"
+    );
+}
+
+
+/* main program starts here */
+void bootloader(unsigned char check_reset) {
+  uint8_t ch;
+
+  /*
+   * Making these local and in registers prevents the need for initializing
+   * them, and also saves space because code no longer stores to memory.
+   * (initializing address keeps the compiler happy, but isn't really
+   *  necessary, and uses 4 bytes of flash.)
+   */
+  register addr16_t address;
+  register pagelen_t  length;
+
+  // After the zero init loop, this is the first code to run.
+  //
+  // This code makes the following assumptions:
+  //  No interrupts will execute
+  //  SP points to RAMEND
+  //  r1 contains zero
+  //
+  // If not, uncomment the following instructions:
+  // cli();
+  asm volatile ("  clr __zero_reg__");
+
+#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8515__) ||  \
+  defined(__AVR_ATmega8535__) || defined (__AVR_ATmega16__) ||  \
+  defined (__AVR_ATmega32__) || defined (__AVR_ATmega64__)  ||  \
+  defined (__AVR_ATmega128__) || defined (__AVR_ATmega162__)
+  SP=RAMEND;  // This is done by hardware reset on newer chips
+#endif
+
+#if defined(OSCCAL_VALUE)
+  OSCCAL = OSCCAL_VALUE;
+#endif
+
+  /*
+   * Protect as much from MCUSR as possible for application
+   * and still skip bootloader if not necessary
+   *
+   * Code by MarkG55
+   * see discussion in https://github.com/Optiboot/optiboot/issues/97
+   */
+#ifndef MCUSR  // Backward compatability with old AVRs
+#define MCUSR MCUCSR
+#endif
+#if (START_APP_ON_EXTR == 0 && NO_START_APP_ON_POR == 0)
+  /*
+   * Normal behavior.  Start if EXTRF in on and WDRF is off
+   */
+#  define APP_START_REASONS ((ch & (_BV(WDRF) | _BV(EXTRF))) != _BV(EXTRF))
+#  define WDRF_CLR_REASONS (ch & _BV(EXTRF))
+#elif (START_APP_ON_EXTR && NO_START_APP_ON_POR)
+  /*
+   * If NO_START_APP_ON_POR is defined, run bootloader after POR.
+   * This allows use with reset disabled: power on and immediately
+   * program.
+   */
+#  define APP_START_REASONS ((ch & (_BV(PORF) | _BV(WDRF) | _BV(EXTRF))) != _BV(PORF))
+#  define WDRF_CLR_REASONS ((ch & (_BV(PORF) | _BV(WDRF))) == (_BV(PORF) | _BV(WDRF)))
+#elif ((START_APP_ON_EXTR == 0) && NO_START_APP_ON_POR)
+  /*
+   * If START_APP_ON_EXTR is defined, don't run bootloader after
+   * an external reset - only useful in combination with above,
+   * for some unusual use cases.
+   */
+#  define APP_START_REASONS (ch & _BV(WDRF))
+#  define WDRF_CLR_REASONS (ch & (_BV(PORF) | _BV(EXTRF)))
+#else
+  /*
+   * Only run bootloader via jmp to 0 with MCUSR==0.
+   * Probably an error.
+   */
+#  warning "Bootloader can only start via app request because "
+#  warning "START_APP_ON_EXTR is defined and NO_START_APP_ON_POR isn't"
+#  define APP_START_REASONS 1 /* Always start rge App. */
+#  define WDRF_CLR_REASONS 0  /* Never clear WDRF */
+#endif
+
+  ch = MCUSR;
+
+  // Skip all logic and run bootloader if MCUSR is cleared (application request)
+  if (check_reset && ch != 0) {
+    /*
+     * To run the boot loader, External Reset Flag must be set.
+     * If not, we could make shortcut and jump directly to application code.
+     * Also WDRF set with EXTRF is a result of Optiboot timeout, so we
+     * shouldn't run bootloader in loop :-) That's why:
+     *  1. application is running if WDRF is cleared
+     *  2. we clear WDRF if it's set with EXTRF to avoid loops
+     * One problematic scenario: broken application code sets watchdog timer
+     * without clearing MCUSR before and triggers it quickly. But it's
+     * recoverable by power-on with pushed reset button.
+     */
+
+    if (APP_START_REASONS) {
+      if (WDRF_CLR_REASONS) {
+        /*
+         * Clear WDRF if it was most probably set by wdr in bootloader.
+         */
+        if ((uint16_t)&MCUSR > 0x1F) {
+          MCUSR = ~(_BV(WDRF));   // optimize to LDI/OUT
+        } else {
+          MCUSR &= ~(_BV(WDRF));  // or optimize to CBI if possible
+        }
+      }
+      /*
+       * 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" (ch));
+
+      // switch off watchdog
+      watchdogConfig(WATCHDOG_OFF);
+      // Note that appstart_vec is defined so that this works with either
+      // real or virtual boot partitions.
+      __asm__ __volatile__ (
+        // Jump to 'save' or RST vector
+#ifdef VIRTUAL_BOOT_PARTITION
+        // full code version for virtual boot partition
+        "  ldi r30,%[rstvec]\n"
+        "  clr r31\n"
+        "  ijmp\n"::[rstvec] "M"(appstart_vec)
+#else
+#ifdef RAMPZ
+        // use absolute jump for devices with lot of flash
+        "  jmp 0\n"::
+#else
+        // use rjmp to go around end of flash to address 0
+        // it uses fact that optiboot_version constant is 2 bytes before end of flash
+        "  rjmp optiboot_version+2\n"
+#endif //RAMPZ
+#endif //VIRTUAL_BOOT_PARTITION
+        );
+    }
+  } //end handling of MCUSR !=0
+
+#if LED_START_FLASHES > 0
+  // Set up Timer 1 for timeout counter
+#if defined(__AVR_ATtiny261__)||defined(__AVR_ATtiny461__)||defined(__AVR_ATtiny861__)
+  TCCR1B = 0x0E; //div 8196 - we could divide by less since it's a 10-bit counter, but why?
+#elif defined(__AVR_ATtiny25__)||defined(__AVR_ATtiny45__)||defined(__AVR_ATtiny85__)
+  TCCR1 = 0x0E; //div 8196 - it's an 8-bit timer.
+#elif defined(__AVR_ATtiny43__)
+#error "LED flash for Tiny43 not yet supported"
+#else
+  TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
+#endif
+#endif
+
+
+#if (SOFT_UART == 0)
+#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega8515__) || \
+  defined (__AVR_ATmega8535__) || defined (__AVR_ATmega16__) || \
+  defined (__AVR_ATmega32__)
+#if (SINGLESPEED == 0)
+  UCSRA = _BV(U2X); //Double speed mode USART
+#endif //singlespeed
+  UCSRB = _BV(RXEN) | _BV(TXEN);  // enable Rx & Tx
+  UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);  // config USART; 8N1
+  UBRRL = (uint8_t)BAUD_SETTING;
+#else // mega8/etc
+#ifdef LIN_UART
+  //DDRB|=3;
+  LINCR = (1 << LSWRES);
+  //LINBRRL = (((F_CPU * 10L / 32L / BAUD_RATE) + 5L) / 10L) - 1;
+  LINBRRL=(uint8_t)BAUD_SETTING;
+  LINBTR = (1 << LDISR) | (8 << LBT0); 
+  LINCR = _BV(LENA) | _BV(LCMD2) | _BV(LCMD1) | _BV(LCMD0);
+  LINDAT=0;
+#else
+#if (SINGLESPEED == 0)
+  UART_SRA = _BV(U2X0); //Double speed mode USART0
+#endif
+  UART_SRB = _BV(RXEN0) | _BV(TXEN0);
+  UART_SRC = _BV(UCSZ00) | _BV(UCSZ01);
+  UART_SRL = (uint8_t)BAUD_SETTING;
+#endif // LIN_UART
+#endif // mega8/etc
+#endif // soft_uart
+
+#ifdef RS485
+  RS485_DDR |= _BV(RS485_BIT);
+  #ifdef RS485_INVERT
+  RS485_PORT |= _BV(RS485_BIT);
+  #else
+  RS485_PORT &= ~_BV(RS485_BIT);
+  #endif
+#endif
+
+  // Set up watchdog to trigger after desired timeout
+  watchdogConfig(WDTPERIOD);
+
+#if (LED_START_FLASHES > 0) || LED_DATA_FLASH || LED_START_ON
+  /* Set LED pin as output */
+  LED_DDR |= _BV(LED);
+#endif
+  /* hold POWER_ON (GPStracker) */
+  DDRA |= _BV(PA3);
+  PORTA |= _BV(PA3);
+
+#if SOFT_UART
+  /* Set TX pin as HIGH output */
+  UART_PORT |= _BV(UART_TX_BIT);
+  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);
+#else
+#if LED_START_ON
+  /* Turn on LED to indicate starting bootloader (less code!) */
+  LED_PORT |= _BV(LED);
+#endif
+#endif
+
+  /* Forever loop: exits by causing WDT reset */
+  for (;;) {
+    /* get character from UART */
+    ch = getch();
+
+//	putch(ch);
+	/*continue;*/
+    if (ch == STK_GET_SYNC) {
+      verifySpace();
+    }
+    else if (ch == STK_GET_PARAMETER) {
+      unsigned char which = getch();
+      verifySpace();
+      /*
+       * Send optiboot version as "SW version"
+       * Note that the references to memory are optimized away.
+       */
+      if (which == STK_SW_MINOR) {
+        putch(optiboot_version & 0xFF);
+      } else if (which == STK_SW_MAJOR) {
+        putch(optiboot_version >> 8);
+      } 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
+      address.bytes[0] = getch();
+      address.bytes[1] = getch();
+#ifdef RAMPZ
+      // Transfer top bit to LSB in RAMPZ
+      if (address.bytes[1] & 0x80) {
+        RAMPZ |= 0x01;
+      }
+      else {
+        RAMPZ &= 0xFE;
+      }
+#endif
+      address.word *= 2; // Convert from word address to byte address
+      verifySpace();
+    }
+    else if (ch == STK_UNIVERSAL) {
+#ifdef RAMPZ
+      // LOAD_EXTENDED_ADDRESS is needed in STK_UNIVERSAL for addressing more than 128kB
+      if ( AVR_OP_LOAD_EXT_ADDR == getch() ) {
+        // get address
+        getch();  // get '0'
+        RAMPZ = (RAMPZ & 0x01) | ((getch() << 1) & 0xff);  // get address and put it in RAMPZ
+        getNch(1); // get last '0'
+        // response
+        putch(0x00);
+      }
+      else {
+        // everything else is ignored
+        getNch(3);
+        putch(0x00);
+      }
+#else
+      // UNIVERSAL command is ignored
+      getNch(4);
+      putch(0x00);
+#endif
+    }
+    /* 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 desttype;
+      uint8_t *bufPtr;
+      pagelen_t savelength;
+
+      GETLENGTH(length);
+      savelength = length;
+      desttype = getch();
+
+      // read a page worth of contents
+      bufPtr = buff.bptr;
+      do *bufPtr++ = getch();
+      while (--length);
+
+      // Read command terminator, start reply
+      verifySpace();
+
+#ifdef VIRTUAL_BOOT_PARTITION
+/*
+ *              How the Virtual Boot Partition works:
+ * At the beginning of a normal AVR program are a set of vectors that
+ * implement the interrupt mechanism.  Each vector is usually a single
+ * instruction that dispatches to the appropriate ISR.
+ * The instruction is normally an rjmp (on AVRs with 8k or less of flash)
+ * or jmp instruction, and the 0th vector is executed on reset and jumps
+ * to the start of the user program:
+ * vectors: jmp startup
+ *          jmp ISR1
+ *          jmp ISR2
+ *             :      ;; etc
+ *          jmp lastvector
+ * To implement the "Virtual Boot Partition", Optiboot detects when the
+ * flash page containing the vectors is being programmed, and replaces the
+ * startup vector with a jump to te beginning of Optiboot.  Then it saves
+ * the applications's startup vector in another (must be unused by the
+ * application), and finally programs the page with the changed vectors.
+ * Thereafter, on reset, the vector will dispatch to the beginning of
+ * Optiboot.  When Optiboot decides that it will run the user application,
+ * it fetches the saved start address from the unused vector, and jumps
+ * there.
+ * The logic is dependent on size of flash, and whether the reset vector is
+ * on the same flash page as the saved start address.
+ */
+
+#if FLASHEND > 8192
+/*
+ * AVR with 4-byte ISR Vectors and "jmp"
+ * WARNING: this works only up to 128KB flash!
+ */
+#if FLASHEND > (128*1024)
+#error "Can't use VIRTUAL_BOOT_PARTITION with more than 128k of Flash"
+#endif
+      if (address.word == RSTVEC_ADDRESS) {
+        // This is the reset vector page. We need to live-patch the
+        // code so the bootloader runs first.
+        //
+        // Save jmp targets (for "Verify")
+        rstVect0_sav = buff.bptr[rstVect0];
+        rstVect1_sav = buff.bptr[rstVect1];
+
+        // Add "jump to Optiboot" at RESET vector
+        // WARNING: this works as long as 'main' is in first section
+        buff.bptr[rstVect0] = ((uint16_t)pre_main) & 0xFF;
+        buff.bptr[rstVect1] = ((uint16_t)pre_main) >> 8;
+
+#if (SAVVEC_ADDRESS != RSTVEC_ADDRESS)
+// the save_vector is not necessarilly on the same flash page as the reset
+//  vector.  If it isn't, we've waiting to actually write it.
+      } else if (address.word == SAVVEC_ADDRESS) {
+        // Save old values for Verify
+        saveVect0_sav = buff.bptr[saveVect0 - SAVVEC_ADDRESS];
+        saveVect1_sav = buff.bptr[saveVect1 - SAVVEC_ADDRESS];
+
+        // Move RESET jmp target to 'save' vector
+        buff.bptr[saveVect0 - SAVVEC_ADDRESS] = rstVect0_sav;
+        buff.bptr[saveVect1 - SAVVEC_ADDRESS] = rstVect1_sav;
+      }
+#else
+      // Save old values for Verify
+      saveVect0_sav = buff.bptr[saveVect0];
+      saveVect1_sav = buff.bptr[saveVect1];
+
+      // Move RESET jmp target to 'save' vector
+      buff.bptr[saveVect0] = rstVect0_sav;
+      buff.bptr[saveVect1] = rstVect1_sav;
+    }
+#endif
+
+#else  // bigger flash
+#ifdef KeepBracesMatched
+    {
+#endif
+/*
+ * AVR with 2-byte ISR Vectors and rjmp
+ */
+      if (address.word == rstVect0) {
+        // This is the reset vector page. We need to live-patch
+        // the code so the bootloader runs first.
+        //
+        // Move RESET vector to 'save' vector
+        // Save jmp targets (for "Verify")
+        rstVect0_sav = buff.bptr[rstVect0];
+        rstVect1_sav = buff.bptr[rstVect1];
+        addr16_t vect;
+        vect.word = ((uint16_t)pre_main-1);
+        // Instruction is a relative jump (rjmp), so recalculate.
+        // an RJMP instruction is 0b1100xxxx xxxxxxxx, so we should be able to
+        // do math on the offsets without masking it off first.
+        // Note that rjmp is relative to the already incremented PC, so the
+        //  offset is one less than you might expect.
+        buff.bptr[0] = vect.bytes[0]; // rjmp to start of bootloader
+        buff.bptr[1] = vect.bytes[1] | 0xC0;  // make an "rjmp"
+#if (SAVVEC_ADDRESS != RSTVEC_ADDRESS)
+      } else if (address.word == SAVVEC_ADDRESS) {
+        addr16_t vect;
+        vect.bytes[0] = rstVect0_sav;
+        vect.bytes[1] = rstVect1_sav;
+        // Save old values for Verify
+        saveVect0_sav = buff.bptr[saveVect0 - SAVVEC_ADDRESS];
+        saveVect1_sav = buff.bptr[saveVect1 - SAVVEC_ADDRESS];
+
+        vect.word = (vect.word-save_vect_num); //substract 'save' interrupt position
+        // Move RESET jmp target to 'save' vector
+        buff.bptr[saveVect0 - SAVVEC_ADDRESS] = vect.bytes[0];
+        buff.bptr[saveVect1 - SAVVEC_ADDRESS] = (vect.bytes[1] & 0x0F)| 0xC0;  // make an "rjmp"
+      }
+#else
+#ifdef KeepBracesMatched
+      {
+#endif
+
+        // Save old values for Verify
+        saveVect0_sav = buff.bptr[saveVect0];
+        saveVect1_sav = buff.bptr[saveVect1];
+
+        vect.bytes[0] = rstVect0_sav;
+        vect.bytes[1] = rstVect1_sav;
+        vect.word = (vect.word-save_vect_num); //substract 'save' interrupt position
+        // Move RESET jmp target to 'save' vector
+        buff.bptr[saveVect0] = vect.bytes[0];
+        buff.bptr[saveVect1] = (vect.bytes[1] & 0x0F)| 0xC0;  // make an "rjmp"
+        // Add rjmp to bootloader at RESET vector
+        vect.word = ((uint16_t)pre_main-1); // (main) is always <= 0x0FFF; no masking needed.
+        buff.bptr[0] = vect.bytes[0]; // rjmp 0x1c00 instruction
+      }
+
+#endif
+
+#endif // FLASHEND
+#endif // VBP
+
+      writebuffer(desttype, buff, address, savelength);
+
+
+    }
+/* Read memory block mode, length is big endian.  */
+    else if (ch == STK_READ_PAGE) {
+      uint8_t desttype;
+      GETLENGTH(length);
+
+      desttype = getch();
+
+      verifySpace();
+
+      read_mem(desttype, address, 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);
+  }
+}
+
+int main(void) {
+	bootloader(1);
+}
+
+__attribute__((section(".manualcall"))) void manual_call(void) {
+	bootloader(0);
+}
+
+void putch(char ch) {
+#if (SOFT_UART == 0)
+  // Hardware UARTs.
+#ifndef LIN_UART
+#ifdef RS485
+  uint8_t x;
+  do {
+    x = UART_SRA;
+  } while (!(x & _BV(UDRE0)));
+  // clear transmitted flag
+  x |= _BV(TXC0);
+  UART_SRA = x;
+  // put transceiver to output mode
+# ifdef RS485_INVERT
+  RS485_PORT &= ~_BV(RS485_BIT);
+# else
+  RS485_PORT |= _BV(RS485_BIT);
+# endif
+  // put char
+  UART_UDR = ch;
+  // wait for char transmitted
+  while (!(UART_SRA & _BV(TXC0))) {  /* Spin */ }
+  // put transceiver to input mode
+# ifdef RS485_INVERT
+  RS485_PORT |= _BV(RS485_BIT);
+# else
+  RS485_PORT &= ~_BV(RS485_BIT);
+# endif
+#else //not RS485
+  while (!(UART_SRA & _BV(UDRE0))) {  /* Spin */ }
+  UART_UDR = ch;
+#endif
+#else //is LIN UART
+  while (!(LINSIR & _BV(LTXOK)))   {  /* Spin */ }
+  UART_UDR = ch;
+#endif
+
+#else // SOFT_UART
+
+#ifdef RS485
+  // put transceiver to output mode
+  #ifdef RS485_INVERT
+  RS485_PORT &= ~_BV(RS485_BIT);
+  #else
+  RS485_PORT |= _BV(RS485_BIT);
+  #endif
+#endif
+  __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"
+    );
+
+#ifdef RS485
+  // put transceiver to input mode
+  #ifdef RS485_INVERT
+  RS485_PORT |= _BV(RS485_BIT);
+  #else
+  RS485_PORT &= ~_BV(RS485_BIT);
+  #endif
+#endif
+#endif // SOFT_UART
+}
+
+static void inline toggle_led(void) {
+#if defined(__AVR_ATmega8__)    || defined(__AVR_ATmega8515__) ||       \
+  defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__)   ||         \
+  defined(__AVR_ATmega162__)  || defined(__AVR_ATmega32__)   ||         \
+  defined(__AVR_ATmega64__)   || defined(__AVR_ATmega128__)
+  LED_PORT ^= _BV(LED);
+#else
+  LED_PIN |= _BV(LED);  // Newer AVRs can toggle by writing PINx
+#endif
+}
+
+uint8_t getch(void) {
+  uint8_t ch;
+
+#if LED_DATA_FLASH
+  toggle_led();
+#endif
+
+#if SOFT_UART
+  watchdogReset();
+  __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
+#ifndef LIN_UART
+  while (!(UART_SRA & _BV(RXC0)))  {  /* Spin */ }
+  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();
+  }
+#else
+  while (!(LINSIR & _BV(LRXOK)))  {  /* Spin */ }
+  if (!(LINSIR & _BV(LFERR))) {
+    watchdogReset();  /* Eventually abort if wrong speed */
+  }
+#endif
+  ch = UART_UDR;
+#endif
+
+#if LED_DATA_FLASH
+  toggle_led();
+#endif
+
+  return ch;
+}
+
+#if 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
+
+#if UART_B_VALUE < 6
+// (this value is a "guess" at when loop/call overhead might become too
+//  significant for the soft uart to work.  It tests OK with the popular
+//  "ATtinycore" chips that need SOFT_UART, at the usual clock/baud combos.)
+#error Baud rate too high 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 {
+#if defined(__AVR_ATtiny261__)||defined(__AVR_ATtiny461__)||defined(__AVR_ATtiny861__) || defined(__AVR_ATtiny25__)||defined(__AVR_ATtiny45__)||defined(__AVR_ATtiny85__)
+    TCNT1 = 0xFF & (-(F_CPU/(8196L*16)));
+    TIFR = _BV(TOV1);
+    while (!(TIFR & _BV(TOV1)));
+#elif defined(__AVR_ATtiny43__)
+#error "LED flash for Tiny43 not yet supported"
+#else
+    TCNT1 = -(F_CPU/(1024*16));
+    TIFR1 = _BV(TOV1);
+    while (!(TIFR1 & _BV(TOV1)));
+#endif
+
+    toggle_led();
+    watchdogReset();
+#if (SOFT_UART == 0)
+    /*
+     * While in theory, the STK500 initial commands would be buffered
+     *  by the UART hardware, avrdude sends several attempts in rather
+     *  quick succession, some of which will be lost and cause us to
+     *  get out of sync.  So if we see any data; stop blinking.
+     */
+#ifndef LIN_UART
+    if (UART_SRA & _BV(RXC0))
+#else
+      if (LINSIR & _BV(LRXOK))
+#endif
+        break;
+#else
+// This doesn't seem to work?
+//    if ((UART_PIN & (1<<UART_RX_BIT)) == 0)
+//      break;  // detect start bit on soft uart too.
+#endif
+  } while (--count);
+}
+#endif
+
+// Watchdog functions. These are only safe with interrupts turned off.
+void watchdogReset() {
+  __asm__ __volatile__ (
+    "  wdr\n"
+    );
+}
+
+void watchdogConfig(uint8_t x) {
+#ifdef WDCE //does it have a Watchdog Change Enable?
+#ifdef WDTCSR
+  WDTCSR = _BV(WDCE) | _BV(WDE);
+#else
+  WDTCR= _BV(WDCE) | _BV(WDE);
+#endif
+#else //then it must be one of those newfangled ones that use CCP
+  CCP=0xD8; //so write this magic number to CCP
+#endif
+
+#ifdef WDTCSR
+  WDTCSR = x;
+#else
+  WDTCR= x;
+#endif
+}
+
+
+/*
+ * void writebuffer(memtype, buffer, address, length)
+ */
+static inline void writebuffer(int8_t memtype, addr16_t mybuff,
+                               addr16_t address, pagelen_t len)
+{
+  switch (memtype) {
+  case 'E': // EEPROM
+#if SUPPORT_EEPROM || BIGBOOT
+    while (len--) {
+      eeprom_write_byte((address.bptr++), *(mybuff.bptr++));
+    }
+#else
+    /*
+     * On systems where EEPROM write is not supported, just busy-loop
+     * until the WDT expires, which will eventually cause an error on
+     * host system (which is what it should do.)
+     */
+    while (1)
+      ; // Error: wait for WDT
+#endif
+    break;
+  default:  // FLASH
+    /*
+     * Default to writing to Flash program memory.  By making this
+     * the default rather than checking for the correct code, we save
+     * space on chips that don't support any other memory types.
+     */
+    {
+      // Copy buffer into programming buffer
+      uint16_t addrPtr = address.word;
+
+      /*
+       * Start the page erase and wait for it to finish.  There
+       * used to be code to do this while receiving the data over
+       * the serial link, but the performance improvement was slight,
+       * and we needed the space back.
+       */
+#ifdef FOURPAGEERASE
+      if ((address.bytes[0] & ((SPM_PAGESIZE<<2)-1))==0) {
+#endif
+        __boot_page_erase_short(address.word);
+        boot_spm_busy_wait();
+#ifdef FOURPAGEERASE
+      }
+#endif
+
+      /*
+       * Copy data from the buffer into the flash write buffer.
+       */
+      do {
+        __boot_page_fill_short((uint16_t)(void*)addrPtr, *(mybuff.wptr++));
+        addrPtr += 2;
+      } while (len -= 2);
+
+      /*
+       * Actually Write the buffer to flash (and wait for it to finish.)
+       */
+      __boot_page_write_short(address.word);
+      boot_spm_busy_wait();
+#if defined(RWWSRE)
+      // Reenable read access to flash
+      __boot_rww_enable_short();
+#endif
+    } // default block
+    break;
+  } // switch
+}
+
+static inline void read_mem(uint8_t memtype, addr16_t address, pagelen_t length)
+{
+  uint8_t ch;
+
+  switch (memtype) {
+
+#if SUPPORT_EEPROM || BIGBOOT
+  case 'E': // EEPROM
+    do {
+      putch(eeprom_read_byte((address.bptr++)));
+    } while (--length);
+    break;
+#endif
+  default:
+    do {
+#ifdef VIRTUAL_BOOT_PARTITION
+      // Undo vector patch in bottom page so verify passes
+      if (address.word == rstVect0) ch = rstVect0_sav;
+      else if (address.word == rstVect1) ch = rstVect1_sav;
+      else if (address.word == saveVect0) ch = saveVect0_sav;
+      else if (address.word == saveVect1) ch = saveVect1_sav;
+      else ch = pgm_read_byte_near(address.bptr);
+      address.bptr++;
+#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.bptr): "1" (address));
+#else
+      // read a Flash byte and increment the address
+      __asm__ ("  lpm %0,Z+\n" : "=r" (ch), "=z" (address.bptr): "1" (address));
+#endif
+      putch(ch);
+    } while (--length);
+    break;
+  } // switch
+}
+
+
+#if (APP_NOSPM == 0)
+
+/*
+ * Separate function for doing spm stuff
+ * It's needed for application to do SPM, as SPM instruction works only
+ * from bootloader.
+ *
+ * How it works:
+ * - do SPM
+ * - wait for SPM to complete
+ * - if chip have RWW/NRWW sections it does additionaly:
+ *   - if command is WRITE or ERASE, AND data=0 then reenable RWW section
+ *
+ * In short:
+ * If you play erase-fill-write, just set data to 0 in ERASE and WRITE
+ * If you are brave, you have your code just below bootloader in NRWW section
+ *   you could do fill-erase-write sequence with data!=0 in ERASE and
+ *   data=0 in WRITE
+ */
+static void do_spm(uint16_t address, uint8_t command, uint16_t data)  __attribute__ ((used));
+static void do_spm(uint16_t address, uint8_t command, uint16_t data) {
+  // Do spm stuff
+  asm volatile (
+    "  movw  r0, %3\n"
+    "  __wr_spmcsr %0, %1\n"
+    "  spm\n"
+    "  clr  r1\n"
+    :
+    : "i" (_SFR_MEM_ADDR(__SPM_REG)),
+      "r" ((uint8_t)command),
+      "z" ((uint16_t)address),
+      "r" ((uint16_t)data)
+    : "r0"
+    );
+
+  // wait for spm to complete
+  //   it doesn't have much sense for __BOOT_PAGE_FILL,
+  //   but it doesn't hurt and saves some bytes on 'if'
+  boot_spm_busy_wait();
+#if defined(RWWSRE)
+  // this 'if' condition should be: (command == __BOOT_PAGE_WRITE || command == __BOOT_PAGE_ERASE)...
+  // but it's tweaked a little assuming that in every command we are interested in here, there
+  // must be also SELFPRGEN set. If we skip checking this bit, we save here 4B
+  if ((command & (_BV(PGWRT)|_BV(PGERS))) && (data == 0) ) {
+    // Reenable read access to flash
+    __boot_rww_enable_short();
+  }
+#endif
+}
+#endif
+
+
+
+#if BIGBOOT
+/*
+ * Optiboot is designed to fit in 512 bytes, with a minimum feature set.
+ * Some chips have a minimum bootloader size of 1024 bytes, and sometimes
+ * it is desirable to add extra features even though 512bytes is exceedded.
+ * In that case, the BIGBOOT can be used.
+ * Our extra features so far don't come close to filling 1k, so we can
+ * add extra "frivolous" data to the image.   In particular, we can add
+ * information about how Optiboot was built (which options were selected,
+ * what version, all in human-readable form (and extractable from the
+ * binary with avr-strings.)
+ *
+ * This can always be removed or trimmed if more actual program space
+ * is needed in the future.  Currently the data occupies about 160 bytes,
+ */
+#define xstr(s) str(s)
+#define str(s) #s
+
+__attribute__((section(".fini9"))) const char f_delimit = 0xFF;
+
+#define OPTFLASHSECT __attribute__((section(".fini8")))
+#define OPT2FLASH(o) OPTFLASHSECT const char f##o[] = #o "=" xstr(o)
+
+
+#if LED_START_FLASHES
+OPT2FLASH(LED_START_FLASHES);
+#endif
+#if LED_DATA_FLASH
+OPT2FLASH(LED_DATA_FLASH);
+#endif
+#if LED_START_ON
+OPT2FLASH(LED_START_ON);
+#endif
+#ifdef LED_NAME
+OPTFLASHSECT const char f_LED[] = "LED=" LED_NAME;
+#endif
+
+#if SUPPORT_EEPROM
+OPT2FLASH(SUPPORT_EEPROM);
+#endif
+
+#if defined(RS485)
+OPTFLASHSECT const char f_rs485[] = "RS485=" RS485_NAME;
+#endif
+#if BAUD_RATE
+OPT2FLASH(BAUD_RATE);
+#endif
+#if SOFT_UART
+OPT2FLASH(SOFT_UART);
+#endif
+#if defined(UART)
+OPT2FLASH(UART);
+#endif
+
+#if (!defined(NODATE)) || (NODATE == 0)
+// Leave out the date, useful if we want to compare binaries
+OPTFLASHSECT const char f_date[] = "Built:" __DATE__ ":" __TIME__;
+#endif
+#if BIGBOOT
+OPT2FLASH(BIGBOOT);
+#endif
+#ifdef VIRTUAL_BOOT_PARTITION
+OPTFLASHSECT const char f_boot[] = "Virtual_Boot_Partition";
+#endif
+OPT2FLASH(F_CPU);
+OPTFLASHSECT const char f_device[] = "Device=" xstr(__AVR_DEVICE_NAME__);
+#if OPTIBOOT_CUSTOMVER
+OPT2FLASH(OPTIBOOT_CUSTOMVER);
+#endif
+OPTFLASHSECT const char f_version[] = "Version=" xstr(OPTIBOOT_MAJVER) "." xstr(OPTIBOOT_MINVER);
+
+#endif

+ 780 - 0
optiboot/optiboot_x.c

@@ -0,0 +1,780 @@
+/**********************************************************/
+/* Optiboot bootloader for Mega0, Tiny0, Tiny1            */
+/*                                                        */
+/*   https://github.com/optiboot/optiboot                 */
+/*                                                        */
+/* Heavily optimised bootloader that is fast and small    */
+/* (512 bytes, 115200bps                                  */
+/*                                                        */
+/*   Written almost entirely in C                         */
+/*   Customisable timeout with accurate timeconstant      */
+/*                                                        */
+/*                                                        */
+/* Copyright 2013-2021 by Bill Westfield.                 */
+/* Copyright 2010 by Peter Knight.                        */
+/*                                                        */
+/* 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                               */
+/* https://github.com/Optiboot/optiboot/blob/master/LICENSE */
+/*                                                        */
+/**********************************************************/
+
+
+/**********************************************************/
+/*                                                        */
+/* Optional defines:                                      */
+/*                                                        */
+/**********************************************************/
+/*                                                        */
+/* BIGBOOT:                                               */
+/* Build a 1k bootloader, not 512 bytes. This turns on    */
+/* extra functionality.                                   */
+/*                                                        */
+/* BAUD_RATE:                                             */
+/* Set bootloader baud rate.                              */
+/*                                                        */
+/* 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.   */
+/*                                                        */
+/* WDTIME:                                                */
+/* Bootloader timeout period, in seconds.                 */
+/* 1, 2, 4, 8 supported.                                  */
+/*                                                        */
+/* UARTTX:                                                */
+/* UART TX pin (B0, etc) for devices with more than       */
+/* one hardware uart, or alternative pins                 */
+/*                                                        */
+/**********************************************************/
+
+/**********************************************************/
+/* Version Numbers!                                       */
+/*                                                        */
+/* Optiboot now includes a Version number in  the source  */
+/*  and object code, and returns this value via STK500    */
+/*                                                        */
+/* The iniital Mega0/Xtiny support is version 9.          */
+/*  This is very different from normal AVR because of     */
+/*  changed peripherals and unified address space.        */
+/*                                                        */
+/* 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.  The CUSTOM_VERSION=n option      */
+/*  adds n to the high version to facilitate this.        */
+/*                                                        */
+/**********************************************************/
+
+/**********************************************************/
+/* Edit History:                                          */
+/*                                                        */
+/* Jun 2021                                               */
+/* 9.2 add rs485 support and SpenceKonde's startup code   */
+/* Sep 2020                                               */
+/* 9.1 fix do_nvmctrl                                     */
+/* Aug 2019                                               */
+/* 9.0 Refactored for Mega0/Xtiny from optiboot.c         */
+/*   :                                                    */
+/* 4.1 WestfW: put version number in binary.              */
+/**********************************************************/
+
+#define OPTIBOOT_MAJVER 9
+#define OPTIBOOT_MINVER 2
+
+/*
+ * OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
+ * of optiboot.  That way you don't wind up with very different code that
+ * matches the version number of a "released" optiboot.
+ */
+
+#if !defined(OPTIBOOT_CUSTOMVER)
+# define OPTIBOOT_CUSTOMVER 0
+#endif
+
+unsigned const int __attribute__((section(".version"))) __attribute__((used))
+optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER;
+
+
+#include <inttypes.h>
+#include <avr/io.h>
+
+#if (!defined(__AVR_XMEGA__)) || (__AVR_ARCH__ != 103)
+#error CPU not supported by this version of Optiboot.
+#include <unsupported>  // include a non-existent file to stop compilation
+#endif
+
+/*
+ * Fuses.
+ * This is an example of what they'd be like, but some should not
+ * necessarily be under control of the bootloader.  You'll need a
+ * a programmer that processes the .fuses section to actually get
+ * these programmed into the chip.
+ * The fuses actually REQUIRED by Optiboot are:
+ *  BOOTEND=2, SYSCFG0=(CRC off, RSTPIN as appropriate)
+ * On some chips, the "reset" pin can be either RESET or GPIO.
+ *  Other also have the UPDI option. If RESET is not enabled we won't be
+ *  able to auto-reset.  But if the UPDI pin is set to cause RESET, we
+ *  won't be able to reprogram the chip without HV UPDI (which is uncommon.)
+ * The settings show will set chips (ie m4809) with RESET/GPIO to use RESET,
+ *  and chips with RESET/GPIO/UPDI to leave it in UPDI mode - the bootloader
+ *  can still be started by a power-on RESET.
+ */
+FUSES = {
+  .WDTCFG = 0,  /* Watchdog Configuration */
+  .BODCFG = FUSE_BODCFG_DEFAULT,  /* BOD Configuration */
+  .OSCCFG = FREQSEL_20MHZ_gc, /* 20MHz */
+#ifdef FUSE_TCD0CFG_DEFAULT
+  .TCD0CFG = FUSE_TCD0CFG_DEFAULT,  /* TCD0 Configuration */
+#endif
+#ifdef RSTPIN
+  .SYSCFG0 =  CRCSRC_NOCRC_gc | RSTPINCFG_RST_gc, /* RESET is enabled */
+#else
+# ifdef FUSE_RSTPINCFG_gm  // group mask will be defined for triple-func pins
+  .SYSCFG0 =  CRCSRC_NOCRC_gc | RSTPINCFG_UPDI_gc, /* RESET is not yet */
+# else
+  .SYSCFG0 =  CRCSRC_NOCRC_gc, /* RESET is not yet */
+# endif
+#endif
+  .SYSCFG1 = 0x06,  /* startup 32ms */
+  .APPEND = 0,  /* Application Code Section End */
+  .BOOTEND = 2 /* Boot Section End */
+};
+
+
+/*
+ * optiboot uses several "address" variables that are sometimes byte pointers,
+ * sometimes word pointers. sometimes 16bit quantities, and sometimes built
+ * up from 8bit input characters.  avr-gcc is not great at optimizing the
+ * assembly of larger words from bytes, but we can use the usual union to
+ * do this manually.  Expanding it a little, we can also get rid of casts.
+ */
+typedef union {
+  uint8_t  *bptr;
+  uint16_t *wptr;
+  uint16_t word;
+  uint8_t bytes[2];
+} addr16_t;
+
+
+/*
+ * pin_defs.h
+ * This contains most of the rather ugly defines that implement our
+ * ability to use UART=n and LED=D3, and some avr family bit name differences.
+ */
+#include "pin_defs_x.h"
+
+/*
+ * stk500.h contains the constant definitions for the stk500v1 comm protocol
+ */
+#include "stk500.h"
+
+#ifndef LED_START_FLASHES
+# define LED_START_FLASHES 0
+#endif
+
+/*
+ * The mega-0, tiny-0, and tiny-1 chips all reset to running on the
+ *  internal oscillator, with a prescaler of 6.  The internal oscillator
+ *  is either 20MHz or 16MHz, depending on a fuse setting - we can read
+ *  the fuse to figure our which.
+ * The BRG divisor is also fractional, permitting (afaik) any reasonable
+ *  bit rate between about 1000bps and 115200bps. (higher bitrates would
+ *  require changing the default clock.)
+ * This makes the BRG generation a bit different than for prior processors.
+ */
+/* set the UART baud rate defaults */
+#ifndef BAUD_RATE
+# define BAUD_RATE   115200L // Highest rate Avrdude win32 will support
+#endif
+#ifdef F_CPU
+# warning F_CPU is ignored for this chip (run from internal osc.)
+#endif
+#ifdef SINGLESPEED
+# warning SINGLESPEED ignored for this chip. (Fractional BRG)
+#endif
+#ifdef UART
+# warning UART is ignored for this chip (use UARTTX=PortPin instead)
+#endif
+
+#define BAUD_SETTING_16 (((16000000/6)*64) / (16L*BAUD_RATE))
+#define BAUD_ACTUAL_16 ((64L*(16000000/6)) / (16L*BAUD_SETTING))
+#define BAUD_SETTING_20 (((20000000/6)*64) / (16L*BAUD_RATE))
+#define BAUD_ACTUAL_20 ((64L*(20000000/6)) / (16L*BAUD_SETTING))
+
+#if BAUD_SETTING_16 < 64   // divisor must be > 1.  Low bits are fraction.
+# error Unachievable baud rate (too fast) BAUD_RATE
+#endif
+
+#if BAUD_SETTING > 65635
+# error Unachievable baud rate (too slow) BAUD_RATE
+#endif // baud rate slow check
+
+  /*
+   * Watchdog timeout translations from human readable to config vals
+   */
+#ifndef WDTTIME
+# define WDTPERIOD WDT_PERIOD_1KCLK_gc  // 1 second
+#elif WDTTIME == 1
+# define WDTPERIOD WDT_PERIOD_1KCLK_gc  // 1 second
+#elif WDTTIME == 2
+# define WDTPERIOD WDT_PERIOD_2KCLK_gc  // 2 seconds
+#elif WDTTIME == 4
+# define WDTPERIOD WDT_PERIOD_4KCLK_gc  // 4 seconds
+#elif WDTTIME == 8
+# define WDTPERIOD WDT_PERIOD_8KCLK_gc  // 8 seconds
+#else
+#endif
+
+/*
+ * We can never load flash with more than 1 page at a time, so we can save
+ * some code space on parts with smaller pagesize by using a smaller int.
+ */
+#if MAPPED_PROGMEM_PAGE_SIZE > 255
+typedef uint16_t pagelen_t;
+# define GETLENGTH(len) len = getch()<<8; len |= getch()
+#else
+typedef uint8_t pagelen_t;
+# define GETLENGTH(len) (void) getch() /* skip high byte */; len = getch()
+#endif
+
+
+/* Function Prototypes
+ * The main() function is in init9, which removes the interrupt vector table
+ * we don't need. It is also 'OS_main', which means the compiler does not
+ * generate any entry or exit code itself (but unlike 'naked', it doesn't
+ * suppress some compile-time options we want.)
+ */
+
+void pre_main(void) __attribute__ ((naked)) __attribute__ ((section (".init8")));
+int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))) __attribute__((used));
+
+void __attribute__((noinline)) __attribute__((leaf)) putch(char);
+uint8_t __attribute__((noinline)) __attribute__((leaf)) getch(void) ;
+void __attribute__((noinline)) verifySpace();
+void __attribute__((noinline)) watchdogConfig(uint8_t x);
+
+static void getNch(uint8_t);
+
+#if LED_START_FLASHES > 0
+static inline void flash_led(uint8_t);
+#endif
+
+#define watchdogReset()  __asm__ __volatile__ ("  wdr\n")
+
+/*
+ * RAMSTART should be self-explanatory.  It's bigger on parts with a
+ * lot of peripheral registers.
+ * Note that RAMSTART (for optiboot) need not be exactly at the start of RAM.
+ */
+#if !defined(RAMSTART)  // newer versions of gcc avr-libc define RAMSTART
+#error RAMSTART not defined.
+#endif
+
+/* everything that needs to run VERY early */
+void pre_main (void) {
+  // Allow convenient way of calling do_spm function - jump table,
+  //   so entry to this function will always be here, independent
+  //    of compilation, features, etc
+  __asm__ __volatile__ (
+    "  rjmp 1f\n"
+#ifndef APP_NOSPM
+    "  rjmp do_nvmctrl\n"
+#else
+    "  ret\n"   // if do_spm isn't include, return without doing anything
+#endif
+    "1:\n"
+    );
+}
+
+/* main program starts here */
+int main (void) {
+  uint8_t ch;
+
+  /*
+   * Making these local and in registers prevents the need for initializing
+   * them, and also saves space because code no longer stores to memory.
+   * (initializing address keeps the compiler happy, but isn't really
+   *  necessary, and uses 4 bytes of flash.)
+   */
+  register addr16_t address;
+  register pagelen_t  length;
+
+  // This is the first code to run.
+  //
+  // Optiboot C code makes the following assumptions:
+  //  No interrupts will execute
+  //  SP points to RAMEND
+
+  __asm__ __volatile__ ("  clr __zero_reg__\n"); // known-zero required by avr-libc
+#define RESET_EXTERNAL (RSTCTRL_EXTRF_bm|RSTCTRL_UPDIRF_bm|RSTCTRL_SWRF_bm)
+#ifndef FANCY_RESET_LOGIC
+  ch = RSTCTRL.RSTFR;   // get reset cause
+#ifdef START_APP_ON_POR
+  /*
+   * If WDRF is set OR nothing except BORF and PORF are set, that's
+   * not bootloader entry condition so jump to app - this is for when
+   * UPDI pin is used as reset, so we go straight to app on start.
+   * 11/14: NASTY bug - we also need to check for no reset flags being
+   * set (ie, direct entry) and run bootloader in that case, otherwise
+   * bootloader won't run, among other things, after fresh bootloading!
+   */
+
+  if (ch && (ch & RSTCTRL_WDRF_bm ||
+             (!(ch & (~(RSTCTRL_BORF_bm | RSTCTRL_PORF_bm)))))) {
+# ifdef KeepBracesMatched
+  }
+# endif
+#else
+  /*
+   * If WDRF is set OR nothing except BORF is set, that's not
+   * bootloader entry condition so jump to app - let's see if this
+   * works okay or not...
+   */
+  if (ch && (ch & RSTCTRL_WDRF_bm || (!(ch & (~RSTCTRL_BORF_bm))))) {
+#endif
+    /* Start the app.
+     * Dont bother trying to stuff it in r2, which requires heroic
+     * effort to fish out we'll put it in GPIOR0 where it won't get
+     * stomped on.
+     */
+    // __asm__ __volatile__ ("  mov r2, %0\n" :: "r" (ch));
+    RSTCTRL.RSTFR = ch; //clear the reset causes before jumping to app...
+    GPIOR0 = ch; // but, stash the reset cause in GPIOR0 for use by app...
+    watchdogConfig(WDT_PERIOD_OFF_gc);
+    __asm__ __volatile__(
+      "  jmp app\n"
+      );
+  }
+#else
+  /*
+   * Protect as much Reset Cause as possible for application
+   * and still skip bootloader if not necessary
+   */
+  ch = RSTCTRL.RSTFR;
+  if (ch != 0) {
+    /*
+     * We want to run the bootloader when an external reset has occurred.
+     * On these mega0/XTiny chips, there are three types of ext reset:
+     * reset pin (may not exist), UPDI reset, and SW-request reset.
+     * One of these reset causes, together with watchdog reset, should
+     * mean that Optiboot timed out, and it's time to run the app.
+     * Other reset causes (notably poweron) should run the app directly.
+     * If a user app wants to utilize and detect watchdog resets, it
+     * must make sure that the other reset causes are cleared.
+     */
+    if (ch & RSTCTRL_WDRF_bm) {
+      if (ch & RESET_EXTERNAL) {
+        /*
+         * Clear WDRF because it was most probably set by wdr in
+         * bootloader.  It's also needed to avoid loop by broken
+         * application which could prevent entering bootloader.
+         */
+        RSTCTRL.RSTFR = RSTCTRL_WDRF_bm;
+      }
+    }
+    if (!(ch & RESET_EXTERNAL)) {
+      /*
+       * 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"(ch));
+
+      // switch off watchdog
+      watchdogConfig(WDT_PERIOD_OFF_gc);
+      __asm__ __volatile__(
+        "  jmp app\n"
+        );
+    }
+  }
+#endif // Fancy reset cause stuff
+
+  watchdogReset();
+//    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0);  // full speed clock
+
+  MYUART_TXPORT.DIR |= MYUART_TXPIN; // set TX pin to output
+  MYUART_TXPORT.OUT |= MYUART_TXPIN;  // and "1" as per datasheet
+#if defined (MYUART_PMUX_VAL)
+  MYPMUX_REG = MYUART_PMUX_VAL;  // alternate pinout to use
+#endif
+  if ((FUSE_OSCCFG & FUSE_FREQSEL_gm) == FREQSEL_16MHZ_gc) {
+    MYUART.BAUD = BAUD_SETTING_16;
+  } else {
+    MYUART.BAUD = BAUD_SETTING_20;
+  }
+  MYUART.DBGCTRL = 1;  // run during debug
+  MYUART.CTRLC = (USART_CHSIZE_gm & USART_CHSIZE_8BIT_gc);  // Async, Parity Disabled, 1 StopBit
+  MYUART.CTRLA = 0;  // Interrupts: all off
+  MYUART.CTRLB = USART_RXEN_bm | USART_TXEN_bm;
+
+#ifdef RS485
+  RS485_PORT.DIR |= _BV(RS485_BIT);
+#endif
+
+  // Set up watchdog to trigger after a bit
+  //  (nominally:, 1s for autoreset, longer for manual)
+  watchdogConfig(WDTPERIOD);
+
+#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) || defined(LED_START_ON)
+  /* Set LED pin as output */
+  LED_PORT.DIR |= LED;
+#endif
+
+#if LED_START_FLASHES > 0
+  /* Flash onboard LED to signal entering of bootloader */
+# ifdef LED_INVERT
+  flash_led(LED_START_FLASHES * 2+1);
+# else
+  flash_led(LED_START_FLASHES * 2);
+# endif
+#else
+#if defined(LED_START_ON)
+# ifndef LED_INVERT
+  /* Turn on LED to indicate starting bootloader (less code!) */
+  LED_PORT.OUT |= LED;
+# endif
+#endif
+#endif
+
+  /* Forever loop: exits by causing WDT reset */
+  for (;;) {
+    /* get character from UART */
+    ch = getch();
+
+    if(ch == STK_GET_PARAMETER) {
+      unsigned char which = getch();
+      verifySpace();
+      /*
+       * Send optiboot version as "SW version"
+       * Note that the references to memory are optimized away.
+       */
+      if (which == STK_SW_MINOR) {
+        putch(optiboot_version & 0xFF);
+      } else if (which == STK_SW_MAJOR) {
+        putch(optiboot_version >> 8);
+      } 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
+      address.bytes[0] = getch();
+      address.bytes[1] = getch();
+      // ToDo: will there be mega-0 chips with >128k of RAM?
+/*          UPDI chips apparently have byte-addressable FLASH ?
+            address.word *= 2; // Convert from word address to byte address
+*/
+      verifySpace();
+    }
+    else if(ch == STK_UNIVERSAL) {
+#ifndef RAMPZ
+      // UNIVERSAL command is ignored
+      getNch(4);
+      putch(0x00);
+#endif
+    }
+    /* Write memory, length is big endian and is in bytes */
+    else if(ch == STK_PROG_PAGE) {
+      // PROGRAM PAGE - any kind of page!
+      uint8_t desttype;
+
+      GETLENGTH(length);
+      desttype = getch();
+
+      if (desttype == 'F') {
+        address.word += MAPPED_PROGMEM_START;
+      } else {
+        address.word += MAPPED_EEPROM_START;
+      }
+      // TODO: user row?
+
+      do {
+        *(address.bptr++) = getch();
+      } while (--length);
+
+      // Read command terminator, start reply
+      verifySpace();
+      /*
+       * Actually Write the buffer to flash (and wait for it to finish.)
+       */
+      _PROTECTED_WRITE_SPM(NVMCTRL.CTRLA, NVMCTRL_CMD_PAGEERASEWRITE_gc);
+      while (NVMCTRL.STATUS & (NVMCTRL_FBUSY_bm|NVMCTRL_EEBUSY_bm))
+        ; // wait for flash and EEPROM not busy, just in case.
+    }
+    /* Read memory block mode, length is big endian.  */
+    else if(ch == STK_READ_PAGE) {
+      uint8_t desttype;
+      GETLENGTH(length);
+
+      desttype = getch();
+
+      verifySpace();
+      if (desttype == 'F') {
+        address.word += MAPPED_PROGMEM_START;
+      } else {
+        address.word += MAPPED_EEPROM_START;
+      }
+      // TODO: user row?
+
+      do {
+        putch(*(address.bptr++));
+      } while (--length);
+    }
+
+    /* Get device signature bytes */
+    else if(ch == STK_READ_SIGN) {
+      // READ SIGN - return actual device signature from SIGROW
+      // this enables the same binary to be ued on multiple chips.
+      verifySpace();
+      putch(SIGROW_DEVICEID0);
+      putch(SIGROW_DEVICEID1);
+      putch(SIGROW_DEVICEID2);
+    }
+    else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
+      // Adaboot no-wait mod
+      watchdogConfig(WDT_PERIOD_8CLK_gc);
+      verifySpace();
+    }
+    else {
+      // This covers the response to commands like STK_ENTER_PROGMODE
+      verifySpace();
+    }
+    putch(STK_OK);
+  }
+}
+
+#if RS485
+inline void rs485_txon() {
+# ifdef RS485_INVERT
+  RS485_PORT.OUT &= ~_BV(RS485_BIT);
+# else
+  RS485_PORT.OUT |= _BV(RS485_BIT);
+# endif
+}
+inline void rs485_txoff() {
+// First, wait for any pending transmits to finish.
+  MYUART.STATUS = USART_TXCIF_bm;  // This clears the TX complete flag
+  while ((MYUART.STATUS & USART_TXCIF_bm) == 0)
+    ; // spin loop waiting for TX Complete (could be immediately)
+# ifdef RS485_INVERT
+  RS485_PORT.OUT |= _BV(RS485_BIT);
+# else
+  RS485_PORT.OUT &= ~_BV(RS485_BIT);
+# endif
+}
+#else // provide null functions to be optimized away.
+inline void rs485_txon() {}
+inline void rs485_txoff() {}
+#endif
+
+void putch (char ch) {
+  rs485_txon();  // turn on and leave on till we're done xmitting.
+  while (0 == (MYUART.STATUS & USART_DREIF_bm))
+    ;
+  MYUART.TXDATAL = ch;
+  rs485_txoff();    // To receive, turn off transmitter
+}
+
+uint8_t getch (void) {
+  uint8_t ch, flags;
+  while (!(MYUART.STATUS & USART_RXCIF_bm))
+    ;
+  flags = MYUART.RXDATAH;
+  ch = MYUART.RXDATAL;
+  if ((flags & USART_FERR_bm) == 0)
+    watchdogReset();
+#ifdef LED_DATA_FLASH
+  LED_PORT.IN |= LED;
+#endif
+
+  return ch;
+}
+
+void getNch (uint8_t count) {
+  do getch(); while (--count);
+  verifySpace();
+}
+
+void verifySpace () {
+  if (getch() != CRC_EOP) {
+    watchdogConfig(WDT_PERIOD_8CLK_gc);    // 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) {
+  uint16_t delay;  // at 20MHz/6, a 16bit delay counter is enough
+  while (count--) {
+    LED_PORT.IN |= LED;
+    // delay assuming 20Mhz OSC.  It's only to "look about right", anyway.
+    for (delay = ((20E6/6)/150); delay; delay--) {
+      watchdogReset();
+      if (MYUART.STATUS & USART_RXCIF_bm)
+        return;
+    }
+  }
+  watchdogReset(); // for breakpointing
+}
+#endif
+
+
+/*
+ * Change the watchdog configuration.
+ *  Could be a new timeout, could be off...
+ */
+void watchdogConfig (uint8_t x) {
+  while(WDT.STATUS & WDT_SYNCBUSY_bm)
+    ;  // Busy wait for sycnhronization is required!
+  _PROTECTED_WRITE(WDT.CTRLA, x);
+}
+
+
+#ifndef APP_NOSPM
+/*
+ * Separate function for doing nvmctrl stuff.
+ * It's needed for application to do manipulate flash, since only the
+ *  bootloader can write or erase flash, or write to the flash alias areas.
+ * Note that this is significantly different in the details than the
+ *  do_spm() function provided on older AVRs.  Same "vector", though.
+ *
+ * How it works:
+ * - if the "command" is legal, write it to NVMCTRL.CTRLA
+ * - if the command is not legal, store data to *address
+ * - wait for NVM to complete
+ *
+ * For example, to write a flash page:
+ * Copy each byte with
+ *   do_nvmctrl(flashOffset+MAPPED_PROGMEM_START, 0xFF, *inputPtr);
+ * Erase and write page with
+ *   do_nvmctrl(0, NVMCTRL_CMD_PAGEERASEWRITE_gc, 0);
+ */
+static void do_nvmctrl(uint16_t address, uint8_t command, uint8_t data)  __attribute__ ((used));
+static void do_nvmctrl (uint16_t address, uint8_t command, uint8_t data) {
+  if (command <= NVMCTRL_CMD_gm) {
+    _PROTECTED_WRITE_SPM(NVMCTRL.CTRLA, command);
+    while (NVMCTRL.STATUS & (NVMCTRL_FBUSY_bm|NVMCTRL_EEBUSY_bm))
+      ; // wait for flash and EEPROM not busy, just in case.
+  } else {
+    *(uint8_t *)address = data;
+  }
+}
+#endif
+
+
+#ifdef BIGBOOT
+/*
+ * Optiboot is designed to fit in 512 bytes, with a minimum feature set.
+ * Some chips have a minimum bootloader size of 1024 bytes, and sometimes
+ * it is desirable to add extra features even though 512bytes is exceedded.
+ * In that case, the BIGBOOT can be used.
+ * Our extra features so far don't come close to filling 1k, so we can
+ * add extra "frivolous" data to the image.   In particular, we can add
+ * information about how Optiboot was built (which options were selected,
+ * what version, all in human-readable form (and extractable from the
+ * binary with avr-strings.)
+ *
+ * This can always be removed or trimmed if more actual program space
+ * is needed in the future.  Currently the data occupies about 160 bytes,
+ */
+#define xstr(s) str(s)
+#define str(s) #s
+#define OPTFLASHSECT __attribute__((section(".fini8")))
+#define OPT2FLASH(o) OPTFLASHSECT const char f##o[] = #o "=" xstr(o)
+
+__attribute__((section(".fini9"))) const char f_delimit = 0xFF;
+
+#ifdef LED_START_FLASHES
+OPT2FLASH(LED_START_FLASHES);
+#endif
+#ifdef LED_DATA_FLASH
+OPT2FLASH(LED_DATA_FLASH);
+#endif
+#ifdef LED_START_ON
+OPT2FLASH(LED_START_ON);
+#endif
+#ifdef LED_NAME
+OPTFLASHSECT const char f_LED[] = "LED=" LED_NAME;
+#endif
+
+#ifdef SUPPORT_EEPROM
+OPT2FLASH(SUPPORT_EEPROM);
+#endif
+
+#if defined(RS485)
+OPTFLASHSECT const char f_rs485[] = "RS485=" RS485_NAME;
+#endif
+#ifdef BAUD_RATE
+OPT2FLASH(BAUD_RATE);
+#endif
+#ifdef UARTTX
+OPTFLASHSECT const char f_uart[] = "UARTTX=" UART_NAME;
+#endif
+
+OPTFLASHSECT const char f_date[] = "Built:" __DATE__ ":" __TIME__;
+#ifdef BIGBOOT
+OPT2FLASH(BIGBOOT);
+#endif
+OPTFLASHSECT const char f_device[] = "Device=" xstr(__AVR_DEVICE_NAME__);
+#ifdef OPTIBOOT_CUSTOMVER
+# if OPTIBOOT_CUSTOMVER != 0
+OPT2FLASH(OPTIBOOT_CUSTOMVER);
+# endif
+#endif
+OPTFLASHSECT const char f_version[] = "Version=" xstr(OPTIBOOT_MAJVER) "." xstr(OPTIBOOT_MINVER);
+
+#endif
+
+// Dummy application that will loop back into the bootloader if not overwritten
+// This gives the bootloader somewhere to jump, and by referencing otherwise
+//  unused variables/functions in the bootloader, it prevents them from being
+//  omitted by the linker, with fewer mysterious link options.
+void  __attribute__((section( ".application")))
+      __attribute__((naked)) app();
+void app()
+{
+  uint8_t ch;
+
+  ch = RSTCTRL.RSTFR;
+  RSTCTRL.RSTFR = ch; // reset causes
+  *(volatile uint16_t *)(&optiboot_version);   // reference the version
+  do_nvmctrl(0, NVMCTRL_CMD_PAGEBUFCLR_gc, 0); // reference this function!
+  __asm__ __volatile__ (
+    "  jmp 0\n"     // similar to running off end of memory
+    );
+//    _PROTECTED_WRITE(RSTCTRL.SWRR, 1); // cause new reset
+}

+ 161 - 0
optiboot/parse_options.mk

@@ -0,0 +1,161 @@
+# Make command-line Options for Optiboot, Optiboot-Mega0
+# Permit commands like "make atmega4809 LED_START_FLASHES=10" to pass the
+# appropriate parameters ("-DLED_START_FLASHES=10") to gcc
+#
+
+ifdef PRODUCTION
+ifneq ($(PRODUCTION),0)
+VERSION_CMD = -DPRODUCTION=1
+endif
+dummy = FORCE
+endif
+
+
+# Build Options
+
+HELPTEXT += "Option CUSTOM_VERSION=nn     - set a customer version number\n"
+ifdef CUSTOM_VERSION
+ifneq ($(CUSTOM_VERSION), 0)
+VERSION_CMD = -DOPTIBOOT_CUSTOMVER=$(CUSTOM_VERSION)
+else
+VERSION_CMD = -DPRODUCTION=1
+endif
+dummy = FORCE
+endif
+
+HELPTEXT += "Option BIGBOOT=1             - enable extra features up to 1kbytes\n"
+# BIGBOOT: Include extra features, up to 1K.
+ifdef BIGBOOT
+ifneq ($(BIGBOOT), 0)
+BIGBOOT_CMD = -DBIGBOOT=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option SUPPORT_EEPROM=1      - Include code to read/write EEPROM\n"
+ifdef SUPPORT_EEPROM
+ifneq ($(SUPPORT_EEPROM), 0)
+SUPPORT_EEPROM_CMD = -DSUPPORT_EEPROM
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option NO_APP_SPM=1          - disallow application call of do_spm\n"
+ifdef NO_APP_SPM
+ifneq ($(NO_APP_SPM),0)
+APPSPM_CMD = -DAPP_NOSPM=1
+endif
+endif
+
+
+# LED options
+
+HELPTEXT += "Option LED=B3                - set LED pin to particular port/bit\n"
+ifdef LED
+LED_CMD = -DLED=$(LED)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option LED_START_FLASHES=n   - set number of LED flashes when bootloader starts\n"
+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
+
+HELPTEXT += "Option LED_DATA_FLASH=1      - flash the LED each time data is received.\n"
+ifdef LED_DATA_FLASH
+ifneq ($(LED_DATA_FLASH), 0)
+LED_DATA_FLASH_CMD = -DLED_DATA_FLASH=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option LED_START_ON=1        - Turn the LED on at bootload start\n"
+ifdef LED_START_ON
+ifneq ($(LED_START_ON), 0)
+LED_START_ON_CMD = -DLED_START_ON=1
+endif
+dummy = FORCE
+endif
+
+HELPTEXT += "Option LED_INVERT=1          - Invert the 'on' state of the LED\n"
+ifdef LED_INVERT
+ifneq ($(LED_INVERT), 0)
+LEDINV_CMD = -DLED_INVERT=1
+endif
+dummy = FORCE
+endif
+
+
+# UART options
+
+HELPTEXT += "Option BAUD_RATE=nnnn        - set the bit rate for communications\n"
+ifdef BAUD_RATE
+BAUD_RATE_CMD = -DBAUD_RATE=$(BAUD_RATE)
+dummy = FORCE
+else
+BAUD_RATE_CMD = -DBAUD_RATE=115200
+endif
+
+HELPTEXT += "Option SOFT_UART=1           - use a software (bit-banged) UART\n"
+ifdef SOFT_UART
+ifneq ($(SOFT_UART), 0)
+SOFT_UART_CMD = -DSOFT_UART=1
+dummy = FORCE
+endif
+endif
+
+HELPTEXT += "Option SINGLESPEED=1         - do not use U2X mode on UART\n"
+ifdef SINGLESPEED
+ifneq ($(SINGLESPEED), 0)
+SS_CMD = -DSINGLESPEED=1
+endif
+endif
+
+HELPTEXT += "Option RS485=B0              - Pin for optional rs485 tx enable\n"
+ifdef RS485
+RS485_CMD = -DRS485=$(RS485)
+dummy = FORCE
+endif
+
+
+#CPU Options
+
+HELPTEXT += "Option TIMEOUT=n             - set WDT to 1, 2, 4, or 8 seconds\n"
+ifdef TIMEOUT
+TIMEOUT_CMD = -DWDTTIME=$(TIMEOUT)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option RESETPIN=0/1          - change RESET pin behavior\n"
+ifdef RESETPIN
+RESETPIN_CMD = -DRSTPIN=$(RESETPIN)
+dummy = FORCE
+endif
+
+ifdef AVR_FREQ
+FCPU_CMD = -DF_CPU=$(AVR_FREQ)
+dummy = FORCE
+endif
+
+HELPTEXT += "Option AVR_FREQ=<n>          - Clock rate of AVR CPU\n"
+
+
+LED_OPTIONS = $(LED_START_FLASHES_CMD) $(LED_DATA_FLASH_CMD) $(LED_CMD) $(LED_START_ON_CMD) $(LEDINV_CMD)
+CPU_OPTIONS = $(RESETPIN_CMD) $(TIMEOUT_CMD) $(FCPU_CMD)
+COMMON_OPTIONS =  $(BIGBOOT_CMD) $(APPSPM_CMD) $(VERSION_CMD)
+COMMON_OPTIONS += $(SUPPORT_EEPROM_CMD)
+
+#UART is handled separately and only passed for devices with more than one.
+HELPTEXT += "Option UART=n                - use UARTn for communications\n"
+HELPTEXT += "Option UARTTX=B5             - describe UART for Mega0, Xtiny\n"
+ifdef UART
+UART_CMD = -DUART=$(UART)
+endif
+ifdef UARTTX
+UART_CMD = -DUARTTX=$(UARTTX)
+endif
+
+UART_OPTIONS = $(UART_CMD) $(BAUD_RATE_CMD) $(SOFT_UART_CMD) $(SS_CMD) $(RS485_CMD)

+ 1630 - 0
optiboot/pin_defs.h

@@ -0,0 +1,1630 @@
+/*
+ * pin_defs.h
+ * optiboot helper defining the default pin assignments (LED, SOFT_UART)
+ * for the various chips that are supported.  This also has some ugly macros
+ * for selecting among various UARTs and LED possibilities using command-line
+ * defines like "UART=2 LED=B5"
+ *
+ * Copyright 2013-2015 by Bill Westfield.
+ * Copyright 2010 by Peter Knight.
+ * This software is licensed under version 2 of the Gnu Public Licence.
+ * See optiboot.c for details.
+ */
+
+/*------------------------------------------------------------------------ */
+#if    defined(__AVR_ATmega168__)       \
+    || defined(__AVR_ATmega168P__)      \
+    || defined(__AVR_ATmega328__)       \
+    || defined(__AVR_ATmega328P__)      \
+    || defined(__AVR_ATmega88)          \
+    || defined(__AVR_ATmega8__)         \
+    || defined(__AVR_ATmega88__)
+/*------------------------------------------------------------------------ */
+
+/*
+ * Onboard LED is connected to pin PB5 in Arduino NG, Diecimila,
+ * Duemilanove, Uno, Nano, and many other Ardunio-like boards.
+ */
+#if !defined(LED)
+#define LED B5
+#endif
+
+/* Ports for soft UART */
+#if 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
+
+/*
+ * 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 (SOFT_UART == 0)
+#if UART == 0
+#if defined(UDR0)
+# define UART_SRA UCSR0A
+# define UART_SRB UCSR0B
+# define UART_SRC UCSR0C
+# define UART_SRL UBRR0L
+# define UART_UDR UDR0
+#elif defined(UDR)
+# define UART_SRA UCSRA
+# define UART_SRB UCSRB
+# define UART_SRC UCSRC
+# define UART_SRL UBRRL
+# define UART_UDR UDR
+#elif defined(LINDAT)
+# define LIN_UART 1
+# define UART_SRA UCSRA
+# define UART_SRB UCSRB
+# define UART_SRC UCSRC
+# define UART_SRL UBRRL
+# define UART_UDR LINDAT
+#else
+# error UART == 0, but no UART0 on device
+#endif
+#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(UDR3)
+#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
+#endif //end #if SOFT_UART==0
+
+#if    defined(__AVR_ATmega8__)         \
+    || defined (__AVR_ATmega32__)       \
+    || defined (__AVR_ATmega16__)
+  //Name conversion R.Wiersma
+  #define UCSR0A        UCSRA
+  #define UDR0          UDR
+  #define UDRE0         UDRE
+  #define RXC0          RXC
+  #define TXC0          TXC
+  #define FE0           FE
+  #define TIFR1         TIFR
+  #define WDTCSR        WDTCR
+#endif
+
+#if    defined (__AVR_ATmega32__)       \
+    || defined (__AVR_ATmega16__)
+  #define WDCE          WDTOE
+#endif
+
+
+/*------------------------------------------------------------------------ */
+/* Sanguino support (and other 40pin DIP cpus) */
+/*------------------------------------------------------------------------ */
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B0
+#endif
+
+/* Fix register names */
+#if defined(__AVR_ATmega8515__)
+#define UCSR0A  UCSRA
+#define UDR0    UDR
+#define UDRE0   UDRE
+#define RXC0    RXC
+#define FE0     FE
+#endif
+#define TIFR1   TIFR
+#define WDTCSR  WDTCR
+
+/* Ports for soft UART */
+#if 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_ATmega8535__)              \
+    || defined(__AVR_ATmega16__)                \
+    || defined(__AVR_ATmega32__)                \
+    || defined(__AVR_ATmega164A__)              \
+    || defined(__AVR_ATmega164P__)              \
+    || defined(__AVR_ATmega324A__)              \
+    || defined(__AVR_ATmega324P__)              \
+    || defined(__AVR_ATmega324PA__)             \
+    || defined(__AVR_ATmega644__)               \
+    || defined(__AVR_ATmega644P__)              \
+    || defined(__AVR_ATmega1284__)              \
+    || defined(__AVR_ATmega1284P__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B0
+#endif
+
+#if     defined(__AVR_ATmega8535__)     \
+    ||  defined(__AVR_ATmega16__)       \
+    ||  defined(__AVR_ATmega32__)
+/* Fix register names */
+#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_ATmega16__) || defined(__AVR_ATmega32__)
+#define WDCE        WDTOE
+#endif
+
+/* Ports for soft UART */
+#if 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_ATmega324PB__)
+/*------------------------------------------------------------------------ */
+
+#if !defined(LED)
+#define LED         B0
+#endif
+
+/* Fix missing register names */
+#define MPCM0   MPCM
+#define U2X0    U2X
+#define UPE0    UPE
+#define DOR0    DOR
+#define FE0     FE
+#define UDRE0   UDRE
+#define TXC0    TXC
+#define RXC0    RXC
+
+#define TXB80   TXB8
+#define RXB80   RXB8
+#define UCSZ02  UCSZ2
+#define TXEN0   TXEN
+#define RXEN0   RXEN
+#define UDRIE0  UDRIE
+#define TXCIE0  TXCIE
+#define RXCIE0  RXCIE
+
+#define UCPOL0  UCPOL
+#define UCSZ00  UCSZ0
+#define UCSZ01  UCSZ1
+#define USBS0   USBS
+#define UPM00   UPM0
+#define UPM01   UPM1
+#define UMSEL00 UMSEL0
+#define UMSEL01 UMSEL1
+
+#define MPCM1   MPCM
+#define U2X1    U2X
+#define UPE1    UPE
+#define DOR1    DOR
+#define FE1     FE
+#define UDRE1   UDRE
+#define TXC1    TXC
+#define RXC1    RXC
+
+#define TXB81   TXB8
+#define RXB81   RXB8
+#define UCSZ12  UCSZ2
+#define TXEN1   TXEN
+#define RXEN1   RXEN
+#define UDRIE1  UDRIE
+#define TXCIE1  TXCIE
+#define RXCIE1  RXCIE
+
+#define UCPOL1  UCPOL
+#define UCSZ10  UCSZ0
+#define UCSZ11  UCSZ1
+#define USBS1   USBS
+#define UPM10   UPM0
+#define UPM11   UPM1
+#define UMSEL10 UMSEL0
+#define UMSEL11 UMSEL1
+
+#define MPCM2   MPCM
+#define U2X2    U2X
+#define UPE2    UPE
+#define DOR2    DOR
+#define FE2     FE
+#define UDRE2   UDRE
+#define TXC2    TXC
+#define RXC2    RXC
+
+#define TXB82   TXB8
+#define RXB82   RXB8
+#define UCSZ22  UCSZ2
+#define TXEN2   TXEN
+#define RXEN2   RXEN
+#define UDRIE2  UDRIE
+#define TXCIE2  TXCIE
+#define RXCIE2  RXCIE
+
+#define UCPOL2  UCPOL
+#define UCSZ20  UCSZ0
+#define UCSZ21  UCSZ1
+#define USBS2   USBS
+#define UPM20   UPM0
+#define UPM21   UPM1
+#define UMSEL20 UMSEL0
+#define UMSEL21 UMSEL1
+
+/* Ports for soft UART */
+#if 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_ATmega64__) || defined(__AVR_ATmega128__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+#define TIFR1 TIFR
+#define WDTCSR WDTCR
+//#define MCUSR MCUCSR
+//#define SPMCR SPMCSR
+
+/* Ports for soft UART */
+#if 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
+
+/*------------------------------------------------------------------------ */
+/* Mega support */
+#if    defined(__AVR_ATmega640__)       \
+    || defined(__AVR_ATmega1280__)      \
+    || defined(__AVR_ATmega128RFA1__)   \
+    || defined(__AVR_ATmega2560__)
+/*------------------------------------------------------------------------ */
+/* Onboard LED is connected to pin PB7 on Arduino Mega */
+#if !defined(LED)
+#define LED         B7
+#endif
+
+/* Ports for soft UART */
+#if 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
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Ports for soft UART */
+#if 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
+
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega169__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Fix register names */
+#define UCSR0A UCSRA
+#define UCSR0B UCSRB
+#define UCSR0C UCSRC
+#define UBRR0L UBRRL
+#define UDR0 UDR
+#define UDRE0 UDRE
+#define RXC0 RXC
+#define FE0 FE
+#define WDTCSR WDTCR
+#define U2X0 U2X
+#define RXEN0 RXEN
+#define TXEN0 TXEN
+#define UCSZ00 UCSZ0
+#define UCSZ01 UCSZ1
+
+/* Ports for soft UART */
+#if 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
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega169P__) || defined(__AVR_ATmega329__) || defined(__AVR_ATmega329P__) \
+|| defined(__AVR_ATmega3290__) || defined(__AVR_ATmega3290P__) || defined(__AVR_ATmega649__) \
+|| defined(__AVR_ATmega649P__) || defined(__AVR_ATmega6490__) || defined(__AVR_ATmega6490P__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Fix register names */
+#define WDTCSR WDTCR
+
+/* Ports for soft UART */
+#if 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
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Ports for soft UART */
+#if 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
+
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega169__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Fix register names */
+#define UCSR0A UCSRA
+#define UCSR0B UCSRB
+#define UCSR0C UCSRC
+#define UBRR0L UBRRL
+#define UDR0 UDR
+#define UDRE0 UDRE
+#define RXC0 RXC
+#define FE0 FE
+#define WDTCSR WDTCR
+#define U2X0 U2X
+#define RXEN0 RXEN
+#define TXEN0 TXEN
+#define UCSZ00 UCSZ0
+#define UCSZ01 UCSZ1
+
+/* Ports for soft UART */
+#if 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
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega169P__) || defined(__AVR_ATmega329__) || defined(__AVR_ATmega329P__) \
+|| defined(__AVR_ATmega3290__) || defined(__AVR_ATmega3290P__) || defined(__AVR_ATmega649__) \
+|| defined(__AVR_ATmega649P__) || defined(__AVR_ATmega6490__) || defined(__AVR_ATmega6490P__)
+/*------------------------------------------------------------------------ */
+#if !defined(LED)
+#define LED         B5
+#endif
+
+/* Fix register names */
+#define WDTCSR WDTCR
+
+/* Ports for soft UART */
+#if 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
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) \
+|| defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U6__) \
+|| defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) \
+|| defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+/*------------------------------------------------------------------------ */
+/* Fix different register names */
+#define MPCM0   MPCM1
+#define U2X0    U2X1
+#define UPE0    UPE1
+#define DOR0    DOR1
+#define FE0     FE1
+#define UDRE0   UDRE1
+#define TXC0    TXC1
+#define RXC0    RXC1
+
+#define TXB80   TXB81
+#define RXB80   RXB81
+#define UCSZ02  UCSZ12
+#define TXEN0   TXEN1
+#define RXEN0   RXEN1
+#define UDRIE0  UDRIE1
+#define TXCIE0  TXCIE1
+#define RXCIE0  RXCIE1
+
+#define UCPOL0  UCPOL1
+#define UCSZ00  UCSZ10
+#define UCSZ01  UCSZ11
+#define USBS0   USBS1
+#define UPM00   UPM10
+#define UPM01   UPM11
+#define UMSEL00 UMSEL10
+#define UMSEL01 UMSEL11
+
+/* Ports for soft UART */
+#if SOFT_UART
+#define UART_PORT   PORTD
+#define UART_PIN    PIND
+#define UART_DDR    DDRD
+#define UART_TX_BIT 3
+#define UART_RX_BIT 2
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__)
+/*------------------------------------------------------------------------ */
+
+#if !defined(LED)
+#define LED         D5 // because of Arduino Uno USB-MCU TXLED
+#endif
+#endif // AtmegaXYu2
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)
+/*------------------------------------------------------------------------ */
+
+#if !defined(LED)
+#define LED         C7 // because of Arduino Micro LED_BUILTIN (D13)
+#endif
+#endif // AtmegaXYu4
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATmega32U6__)
+/*------------------------------------------------------------------------ */
+
+#if !defined(LED)
+#define LED         C6 // because of PWM (OSC3A)
+#endif
+#endif // AtmegaXYu6
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) \
+|| defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+/*------------------------------------------------------------------------ */
+
+#if !defined(LED)
+#define LED         C6 // because of PWM (OSC3A)
+#endif
+#endif // At90usbXYz6/7
+
+
+#endif // usbmcus
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny1634__)
+/*------------------------------------------------------------------------ */
+/* LED is on C0 */
+#if !defined(LED)
+#define LED     C0
+#endif
+#define TIFR1 TIFR
+
+#if 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
+
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny841__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED     B2
+#endif
+
+#if 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
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny441__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B2
+#endif
+
+#if 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
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny84__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B2
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTA
+#define UART_PIN    PINA
+#define UART_DDR    DDRA
+#define UART_TX_BIT 1
+#define UART_RX_BIT 2
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny44__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B2
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTA
+#define UART_PIN    PINA
+#define UART_DDR    DDRA
+#define UART_TX_BIT 1
+#define UART_RX_BIT 2
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny85__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B2
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTB
+#define UART_PIN    PINB
+#define UART_DDR    DDRB
+#define UART_TX_BIT 0
+#define UART_RX_BIT 1
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny45__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B2
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTB
+#define UART_PIN    PINB
+#define UART_DDR    DDRB
+#define UART_TX_BIT 0
+#define UART_RX_BIT 1
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny861__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B3
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTA
+#define UART_PIN    PINA
+#define UART_DDR    DDRA
+#define UART_TX_BIT 6
+#define UART_RX_BIT 7
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny461__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B3
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTA
+#define UART_PIN    PINA
+#define UART_DDR    DDRA
+#define UART_TX_BIT 6
+#define UART_RX_BIT 7
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny88__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B5
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTD
+#define UART_PIN    PIND
+#define UART_DDR    DDRD
+#define UART_TX_BIT 6
+#define UART_RX_BIT 7
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny48__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED   B5
+#endif
+
+#if SOFT_UART
+#define UART_PORT   PORTD
+#define UART_PIN    PIND
+#define UART_DDR    DDRD
+#define UART_TX_BIT 6
+#define UART_RX_BIT 7
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny167__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED     A3
+#endif
+#endif
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny87__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED     A3
+#endif
+#endif
+
+
+/*------------------------------------------------------------------------ */
+#if defined(__AVR_ATtiny828__)
+/*------------------------------------------------------------------------ */
+/* LED is on B2 */
+#if !defined(LED)
+#define LED     B0
+#endif
+
+#define UDRE0 UDRE
+#define FE0 FE
+#define RXC0 RXC
+#define UCSZ00 UCSZ0
+#define UCSZ01 UCSZ1
+#define TXEN0 TXEN
+#define RXEN0 RXEN
+#define U2X0 U2X
+
+
+#if 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
+
+/*
+ * A bunch of macros to enable the LED to be specified as "B5" for bit 5
+ * of port B, and similar.
+ * We define symbols for all the legal combination of port/bit on a chip,
+ * and do pre-processor tests to see if there's a match.  This ends up
+ * being very verbose, but it is pretty easy to generate semi-automatically.
+ * (We wouldn't need this if the preprocessor could do string compares.)
+ */
+
+// Symbols for each PortA bit.
+#define A0 0x100
+#define A1 0x101
+#define A2 0x102
+#define A3 0x103
+#define A4 0x104
+#define A5 0x105
+#define A6 0x106
+#define A7 0x107
+// If there is no PORTA on this chip, don't allow these to be used
+//   (and indicate the error by redefining LED)
+#if !defined(PORTA)
+#if LED >= A0 && LED <= A7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define B0 0x200
+#define B1 0x201
+#define B2 0x202
+#define B3 0x203
+#define B4 0x204
+#define B5 0x205
+#define B6 0x206
+#define B7 0x207
+#if !defined(PORTB)
+#if LED >= B0 && LED <= B7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define C0 0x300
+#define C1 0x301
+#define C2 0x302
+#define C3 0x303
+#define C4 0x304
+#define C5 0x305
+#define C6 0x306
+#define C7 0x307
+#if !(defined(PORTC))
+#if LED >= C0 && LED <= C7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define D0 0x400
+#define D1 0x401
+#define D2 0x402
+#define D3 0x403
+#define D4 0x404
+#define D5 0x405
+#define D6 0x406
+#define D7 0x407
+#if !(defined(PORTD))
+#if LED >= D0 && LED <= D7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define E0 0x500
+#define E1 0x501
+#define E2 0x502
+#define E3 0x503
+#define E4 0x504
+#define E5 0x505
+#define E6 0x506
+#define E7 0x507
+#if !(defined(PORTE))
+#if LED >= E0 && LED <= E7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define F0 0x600
+#define F1 0x601
+#define F2 0x602
+#define F3 0x603
+#define F4 0x604
+#define F5 0x605
+#define F6 0x606
+#define F7 0x607
+#if !(defined(PORTF))
+#if LED >= F0 && LED <= F7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define G0 0x700
+#define G1 0x701
+#define G2 0x702
+#define G3 0x703
+#define G4 0x704
+#define G5 0x705
+#define G6 0x706
+#define G7 0x707
+#if !defined(PORTG)
+#if LED >= G0 && LED <= G7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define H0 0x800
+#define H1 0x801
+#define H2 0x802
+#define H3 0x803
+#define H4 0x804
+#define H5 0x805
+#define H6 0x806
+#define H7 0x807
+#if !(defined(PORTH))
+#if LED >= H0 && LED <= H7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define J0 0xA00
+#define J1 0xA01
+#define J2 0xA02
+#define J3 0xA03
+#define J4 0xA04
+#define J5 0xA05
+#define J6 0xA06
+#define J7 0xA07
+#if !(defined(PORTJ))
+#if LED >= J0 && LED <= J7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define K0 0xB00
+#define K1 0xB01
+#define K2 0xB02
+#define K3 0xB03
+#define K4 0xB04
+#define K5 0xB05
+#define K6 0xB06
+#define K7 0xB07
+#if !(defined(PORTK))
+#if LED >= K0 && LED <= K7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#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 !(defined(PORTL))
+#if LED >= L0 && LED <= L7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+
+/*
+ * A statement like "#if LED == B0" will evaluate (in the preprocessor)
+ * to #if C0 == B0, and then to #if 0x301 == 0x201
+ */
+#if LED == B0
+#define LED_NAME "B0"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB0
+#elif LED == B1
+#define LED_NAME "B1"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB1
+#elif LED == B2
+#define LED_NAME "B2"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB2
+#elif LED == B3
+#define LED_NAME "B3"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB3
+#elif LED == B4
+#define LED_NAME "B4"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB4
+#elif LED == B5
+#define LED_NAME "B5"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB5
+#elif LED == B6
+#define LED_NAME "B6"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB6
+#elif LED == B7
+#define LED_NAME "B7"
+#undef LED
+#define LED_DDR     DDRB
+#define LED_PORT    PORTB
+#define LED_PIN     PINB
+#define LED         PINB7
+
+#elif LED == C0
+#define LED_NAME "C0"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC0
+#elif LED == C1
+#define LED_NAME "C1"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC1
+#elif LED == C2
+#define LED_NAME "C2"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC2
+#elif LED == C3
+#define LED_NAME "C3"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC3
+#elif LED == C4
+#define LED_NAME "C4"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC4
+#elif LED == C5
+#define LED_NAME "C5"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC5
+#elif LED == C6
+#define LED_NAME "C6"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC6
+#elif LED == C7
+#define LED_NAME "C7"
+#undef LED
+#define LED_DDR     DDRC
+#define LED_PORT    PORTC
+#define LED_PIN     PINC
+#define LED         PINC7
+
+#elif LED == D0
+#define LED_NAME "D0"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND0
+#elif LED == D1
+#define LED_NAME "D1"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND1
+#elif LED == D2
+#define LED_NAME "D2"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND2
+#elif LED == D3
+#define LED_NAME "D3"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND3
+#elif LED == D4
+#define LED_NAME "D4"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND4
+#elif LED == D5
+#define LED_NAME "D5"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND5
+#elif LED == D6
+#define LED_NAME "D6"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND6
+#elif LED == D7
+#define LED_NAME "D7"
+#undef LED
+#define LED_DDR     DDRD
+#define LED_PORT    PORTD
+#define LED_PIN     PIND
+#define LED         PIND7
+
+#elif LED == E0
+#define LED_NAME "E0"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE0
+#elif LED == E1
+#define LED_NAME "E1"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE1
+#elif LED == E2
+#define LED_NAME "E2"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE2
+#elif LED == E3
+#define LED_NAME "E3"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE3
+#elif LED == E4
+#define LED_NAME "E4"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE4
+#elif LED == E5
+#define LED_NAME "E5"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE5
+#elif LED == E6
+#define LED_NAME "E6"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE6
+#elif LED == E7
+#define LED_NAME "E7"
+#undef LED
+#define LED_DDR     DDRE
+#define LED_PORT    PORTE
+#define LED_PIN     PINE
+#define LED         PINE7
+
+#elif LED == F0
+#define LED_NAME "F0"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF0
+#elif LED == F1
+#define LED_NAME "F1"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF1
+#elif LED == F2
+#define LED_NAME "F2"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF2
+#elif LED == F3
+#define LED_NAME "F3"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF3
+#elif LED == F4
+#define LED_NAME "F4"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF4
+#elif LED == F5
+#define LED_NAME "F5"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF5
+#elif LED == F6
+#define LED_NAME "F6"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF6
+#elif LED == F7
+#define LED_NAME "F7"
+#undef LED
+#define LED_DDR     DDRF
+#define LED_PORT    PORTF
+#define LED_PIN     PINF
+#define LED         PINF7
+
+#elif LED == G0
+#define LED_NAME "G0"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING0
+#elif LED == G1
+#define LED_NAME "G1"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING1
+#elif LED == G2
+#define LED_NAME "G2"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING2
+#elif LED == G3
+#define LED_NAME "G3"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING3
+#elif LED == G4
+#define LED_NAME "G4"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING4
+#elif LED == G5
+#define LED_NAME "G5"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING5
+#elif LED == G6
+#define LED_NAME "G6"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING6
+#elif LED == G7
+#define LED_NAME "G7"
+#undef LED
+#define LED_DDR     DDRG
+#define LED_PORT    PORTG
+#define LED_PIN     PING
+#define LED         PING7
+
+#elif LED == H0
+#define LED_NAME "H0"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH0
+#elif LED == H1
+#define LED_NAME "H1"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH1
+#elif LED == H2
+#define LED_NAME "H2"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH2
+#elif LED == H3
+#define LED_NAME "H3"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH3
+#elif LED == H4
+#define LED_NAME "H4"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH4
+#elif LED == H5
+#define LED_NAME "H5"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH5
+#elif LED == H6
+#define LED_NAME "H6"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH6
+#elif LED == H7
+#define LED_NAME "H7"
+#undef LED
+#define LED_DDR     DDRH
+#define LED_PORT    PORTH
+#define LED_PIN     PINH
+#define LED         PINH7
+
+#elif LED == J0
+#define LED_NAME "J0"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ0
+#elif LED == J1
+#define LED_NAME "J1"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ1
+#elif LED == J2
+#define LED_NAME "J2"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ2
+#elif LED == J3
+#define LED_NAME "J3"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ3
+#elif LED == J4
+#define LED_NAME "J4"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ4
+#elif LED == J5
+#define LED_NAME "J5"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ5
+#elif LED == J6
+#define LED_NAME "J6"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ6
+#elif LED == J7
+#define LED_NAME "J7"
+#undef LED
+#define LED_DDR     DDRJ
+#define LED_PORT    PORTJ
+#define LED_PIN     PINJ
+#define LED         PINJ7
+
+#elif LED == K0
+#define LED_NAME "K0"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK0
+#elif LED == K1
+#define LED_NAME "K1"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK1
+#elif LED == K2
+#define LED_NAME "K2"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK2
+#elif LED == K3
+#define LED_NAME "K3"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK3
+#elif LED == K4
+#define LED_NAME "K4"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK4
+#elif LED == K5
+#define LED_NAME "K5"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK5
+#elif LED == K6
+#define LED_NAME "K6"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK6
+#elif LED == K7
+#define LED_NAME "K7"
+#undef LED
+#define LED_DDR     DDRK
+#define LED_PORT    PORTK
+#define LED_PIN     PINK
+#define LED         PINK7
+
+#elif LED == L0
+#define LED_NAME "L0"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL0
+#elif LED == L1
+#define LED_NAME "L1"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL1
+#elif LED == L2
+#define LED_NAME "L2"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL2
+#elif LED == L3
+#define LED_NAME "L3"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL3
+#elif LED == L4
+#define LED_NAME "L4"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL4
+#elif LED == L5
+#define LED_NAME "L5"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL5
+#elif LED == L6
+#define LED_NAME "L6"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL6
+#elif LED == L7
+#define LED_NAME "L7"
+#undef LED
+#define LED_DDR     DDRL
+#define LED_PORT    PORTL
+#define LED_PIN     PINL
+#define LED         PINL7
+
+#elif LED == A0
+#define LED_NAME "A0"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA0
+#elif LED == A1
+#define LED_NAME "A1"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA1
+#elif LED == A2
+#define LED_NAME "A2"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA2
+#elif LED == A3
+#define LED_NAME "A3"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA3
+#elif LED == A4
+#define LED_NAME "A4"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA4
+#elif LED == A5
+#define LED_NAME "A5"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA5
+#elif LED == A6
+#define LED_NAME "A6"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA6
+#elif LED == A7
+#define LED_NAME "A7"
+#undef LED
+#define LED_DDR     DDRA
+#define LED_PORT    PORTA
+#define LED_PIN     PINA
+#define LED         PINA7
+
+#else
+// Stop compilation right away, so we don't get more errors.
+#if LED == -1
+#error Unrecognized LED name.  Should be like "B5"
+// Stop compilation right away, so we don't get more errors.
+#pragma GCC diagnostic warning "-Wfatal-errors"
+#error Nonexistent LED PORT.  Check datasheet.
+#endif
+#pragma GCC diagnostic warning "-Wfatal-errors"
+#error Unrecognized LED name.  Should be like "B5"
+#endif
+
+
+#ifdef RS485
+#include "pins_rs485.h"
+#endif
+
+#if SOFT_UART && defined(SOFTTX) && defined(SOFTRX)
+#include "pins_softuart.h"
+#endif

+ 826 - 0
optiboot/pin_defs_x.h

@@ -0,0 +1,826 @@
+/*
+ * pin_defs_x.h
+ * optiboot helper defining the default pin assignments (LED, SOFT_UART)
+ * for the various chips that are supported.  This also has some ugly macros
+ * for selecting among various UARTs and LED possibilities using command-line
+ * defines like "UART=2 LED=B5"
+ *
+ * Copyright 2013-2020 by Bill Westfield.
+ * Copyright 2010 by Peter Knight.
+ * This software is licensed under version 2 of the Gnu Public Licence.
+ * See optiboot.c for details.
+ */
+
+
+/*
+ * A bunch of macros to enable the LED to be specified as "B5" for bit 5
+ * of port B, and similar.
+ * We define symbols for all the legal combination of port/bit on a chip,
+ * and do pre-processor tests to see if there's a match.  This ends up
+ * being very verbose, but it is pretty easy to generate semi-automatically.
+ * (We wouldn't need this if the preprocessor could do string compares.)
+ */
+
+// Symbols for each PortA bit.
+#define A0 0x100
+#define A1 0x101
+#define A2 0x102
+#define A3 0x103
+#define A4 0x104
+#define A5 0x105
+#define A6 0x106
+#define A7 0x107
+// If there is no PORTA on this chip, don't allow these to be used
+//   (and indicate the error by redefining LED)
+#if !defined(PORTA)
+#if LED >= A0 && LED <= A7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define B0 0x200
+#define B1 0x201
+#define B2 0x202
+#define B3 0x203
+#define B4 0x204
+#define B5 0x205
+#define B6 0x206
+#define B7 0x207
+#if !defined(PORTB)
+#if LED >= B0 && LED <= B7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define C0 0x300
+#define C1 0x301
+#define C2 0x302
+#define C3 0x303
+#define C4 0x304
+#define C5 0x305
+#define C6 0x306
+#define C7 0x307
+#if !(defined(PORTC))
+#if LED >= C0 && LED <= C7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define D0 0x400
+#define D1 0x401
+#define D2 0x402
+#define D3 0x403
+#define D4 0x404
+#define D5 0x405
+#define D6 0x406
+#define D7 0x407
+#if !(defined(PORTD))
+#if LED >= D0 && LED <= D7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define E0 0x500
+#define E1 0x501
+#define E2 0x502
+#define E3 0x503
+#define E4 0x504
+#define E5 0x505
+#define E6 0x506
+#define E7 0x507
+#if !(defined(PORTE))
+#if LED >= E0 && LED <= E7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define F0 0x600
+#define F1 0x601
+#define F2 0x602
+#define F3 0x603
+#define F4 0x604
+#define F5 0x605
+#define F6 0x606
+#define F7 0x607
+#if !(defined(PORTF))
+#if LED >= F0 && LED <= F7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define G0 0x700
+#define G1 0x701
+#define G2 0x702
+#define G3 0x703
+#define G4 0x704
+#define G5 0x705
+#define G6 0x706
+#define G7 0x707
+#if !defined(PORTG)
+#if LED >= G0 && LED <= G7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define H0 0x800
+#define H1 0x801
+#define H2 0x802
+#define H3 0x803
+#define H4 0x804
+#define H5 0x805
+#define H6 0x806
+#define H7 0x807
+#if !(defined(PORTH))
+#if LED >= H0 && LED <= H7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define J0 0xA00
+#define J1 0xA01
+#define J2 0xA02
+#define J3 0xA03
+#define J4 0xA04
+#define J5 0xA05
+#define J6 0xA06
+#define J7 0xA07
+#if !(defined(PORTJ))
+#if LED >= J0 && LED <= J7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#define K0 0xB00
+#define K1 0xB01
+#define K2 0xB02
+#define K3 0xB03
+#define K4 0xB04
+#define K5 0xB05
+#define K6 0xB06
+#define K7 0xB07
+#if !(defined(PORTK))
+#if LED >= K0 && LED <= K7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+#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 !(defined(PORTL))
+#if LED >= L0 && LED <= L7
+#undef LED
+#define LED -1
+#endif
+#endif
+
+
+/*
+ * A statement like "#if LED == B0" will evaluation (in the preprocessor)
+ * to #if C0 == B0, and then to #if 0x301 == 0x201
+ */
+#if LED == B0
+#define LED_NAME "B0"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT0)
+#elif LED == B1
+#define LED_NAME "B1"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT1)
+#elif LED == B2
+#define LED_NAME "B2"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT2)
+#elif LED == B3
+#define LED_NAME "B3"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT3)
+#elif LED == B4
+#define LED_NAME "B4"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT4)
+#elif LED == B5
+#define LED_NAME "B5"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT5)
+#elif LED == B6
+#define LED_NAME "B6"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT6)
+#elif LED == B7
+#define LED_NAME "B7"
+#undef LED
+#define LED_PORT    VPORTB
+#define LED         (1<<PORT7)
+
+#elif LED == C0
+#define LED_NAME "C0"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT0)
+#elif LED == C1
+#define LED_NAME "C1"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT1)
+#elif LED == C2
+#define LED_NAME "C2"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT2)
+#elif LED == C3
+#define LED_NAME "C3"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT3)
+#elif LED == C4
+#define LED_NAME "C4"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT4)
+#elif LED == C5
+#define LED_NAME "C5"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT5)
+#elif LED == C6
+#define LED_NAME "C6"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT6)
+#elif LED == C7
+#define LED_NAME "C7"
+#undef LED
+#define LED_PORT    VPORTC
+#define LED         (1<<PORT7)
+
+#elif LED == D0
+#define LED_NAME "D0"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT0)
+#elif LED == D1
+#define LED_NAME "D1"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT1)
+#elif LED == D2
+#define LED_NAME "D2"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT2)
+#elif LED == D3
+#define LED_NAME "D3"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT3)
+#elif LED == D4
+#define LED_NAME "D4"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT4)
+#elif LED == D5
+#define LED_NAME "D5"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT5)
+#elif LED == D6
+#define LED_NAME "D6"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT6)
+#elif LED == D7
+#define LED_NAME "D7"
+#undef LED
+#define LED_PORT    VPORTD
+#define LED         (1<<PORT7)
+
+#elif LED == E0
+#define LED_NAME "E0"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT0)
+#elif LED == E1
+#define LED_NAME "E1"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT1)
+#elif LED == E2
+#define LED_NAME "E2"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT2)
+#elif LED == E3
+#define LED_NAME "E3"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT3)
+#elif LED == E4
+#define LED_NAME "E4"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT4)
+#elif LED == E5
+#define LED_NAME "E5"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT5)
+#elif LED == E6
+#define LED_NAME "E6"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT6)
+#elif LED == E7
+#define LED_NAME "E7"
+#undef LED
+#define LED_PORT    VPORTE
+#define LED         (1<<PORT7)
+
+#elif LED == F0
+#define LED_NAME "F0"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT0)
+#elif LED == F1
+#define LED_NAME "F1"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT1)
+#elif LED == F2
+#define LED_NAME "F2"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT2)
+#elif LED == F3
+#define LED_NAME "F3"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT3)
+#elif LED == F4
+#define LED_NAME "F4"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT4)
+#elif LED == F5
+#define LED_NAME "F5"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT5)
+#elif LED == F6
+#define LED_NAME "F6"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT6)
+#elif LED == F7
+#define LED_NAME "F7"
+#undef LED
+#define LED_PORT    VPORTF
+#define LED         (1<<PORT7)
+
+#elif LED == G0
+#define LED_NAME "G0"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT0)
+#elif LED == G1
+#define LED_NAME "G1"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT1)
+#elif LED == G2
+#define LED_NAME "G2"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT2)
+#elif LED == G3
+#define LED_NAME "G3"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT3)
+#elif LED == G4
+#define LED_NAME "G4"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT4)
+#elif LED == G5
+#define LED_NAME "G5"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT5)
+#elif LED == G6
+#define LED_NAME "G6"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT6)
+#elif LED == G7
+#define LED_NAME "G7"
+#undef LED
+#define LED_PORT    VPORTG
+#define LED         (1<<PORT7)
+
+#elif LED == H0
+#define LED_NAME "H0"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT0)
+#elif LED == H1
+#define LED_NAME "H1"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT1)
+#elif LED == H2
+#define LED_NAME "H2"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT2)
+#elif LED == H3
+#define LED_NAME "H3"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT3)
+#elif LED == H4
+#define LED_NAME "H4"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT4)
+#elif LED == H5
+#define LED_NAME "H5"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT5)
+#elif LED == H6
+#define LED_NAME "H6"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT6)
+#elif LED == H7
+#define LED_NAME "H7"
+#undef LED
+#define LED_PORT    VPORTH
+#define LED         (1<<PORT7)
+
+#elif LED == J0
+#define LED_NAME "J0"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT0)
+#elif LED == J1
+#define LED_NAME "J1"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT1)
+#elif LED == J2
+#define LED_NAME "J2"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT2)
+#elif LED == J3
+#define LED_NAME "J3"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT3)
+#elif LED == J4
+#define LED_NAME "J4"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT4)
+#elif LED == J5
+#define LED_NAME "J5"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT5)
+#elif LED == J6
+#define LED_NAME "J6"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT6)
+#elif LED == J7
+#define LED_NAME "J7"
+#undef LED
+#define LED_PORT    VPORTJ
+#define LED         (1<<PORT7)
+
+#elif LED == K0
+#define LED_NAME "K0"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT0)
+#elif LED == K1
+#define LED_NAME "K1"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT1)
+#elif LED == K2
+#define LED_NAME "K2"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT2)
+#elif LED == K3
+#define LED_NAME "K3"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT3)
+#elif LED == K4
+#define LED_NAME "K4"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT4)
+#elif LED == K5
+#define LED_NAME "K5"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT5)
+#elif LED == K6
+#define LED_NAME "K6"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT6)
+#elif LED == K7
+#define LED_NAME "K7"
+#undef LED
+#define LED_PORT    VPORTK
+#define LED         (1<<PORT7)
+
+#elif LED == L0
+#define LED_NAME "L0"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT0)
+#elif LED == L1
+#define LED_NAME "L1"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT1)
+#elif LED == L2
+#define LED_NAME "L2"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT2)
+#elif LED == L3
+#define LED_NAME "L3"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT3)
+#elif LED == L4
+#define LED_NAME "L4"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT4)
+#elif LED == L5
+#define LED_NAME "L5"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT5)
+#elif LED == L6
+#define LED_NAME "L6"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT6)
+#elif LED == L7
+#define LED_NAME "L7"
+#undef LED
+#define LED_PORT    VPORTL
+#define LED         (1<<PORT7)
+
+#elif LED == A0
+#define LED_NAME "A0"
+#undef LED
+#ifdef VPORTA
+#define LED_PORT    VPORTA.OUT
+#define LED_PORT     VPORTA.IN
+#else
+#define LED_PORT    VPORTA
+#endif
+#define LED         (1<<PORT0)
+#elif LED == A1
+#define LED_NAME "A1"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT1)
+#elif LED == A2
+#define LED_NAME "A2"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT2)
+#elif LED == A3
+#define LED_NAME "A3"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT3)
+#elif LED == A4
+#define LED_NAME "A4"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT4)
+#elif LED == A5
+#define LED_NAME "A5"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT5)
+#elif LED == A6
+#define LED_NAME "A6"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT6)
+#elif LED == A7
+#define LED_NAME "A7"
+#undef LED
+#define LED_PORT    VPORTA
+#define LED         (1<<PORT7)
+
+#else
+// Stop compilation right away, so we don't get more errors.
+#if LED == -1
+#error Unrecognized LED name.  Should be like "B5"
+// Stop compilation right away, so we don't get more errors.
+#pragma GCC diagnostic warning "-Wfatal-errors"
+#error Nonexistent LED PORT.  Check datasheet.
+#endif
+#pragma GCC diagnostic warning "-Wfatal-errors"
+#error Unrecognized LED name.  Should be like "B5"
+#endif
+
+/*
+ * Handle devices with up to 4 uarts.  Rather inelegantly.
+ */
+#define USART_ALTPMUX 1
+
+#if defined(__AVR_ATmega4809__) || defined(__AVR_ATmega4808__) || \
+    defined(__AVR_ATmega3209__) || defined(__AVR_ATmega3208__) || \
+    defined(__AVR_ATmega1609__) || defined(__AVR_ATmega1608__) || \
+    defined(__AVR_ATmega809__) || defined(__AVR_ATmega808__)
+#define MYPMUX_REG PORTMUX.USARTROUTEA
+# if (UARTTX == A0)
+#  define UART_NAME "A0"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTA
+#  define MYUART_TXPIN (1<<PORT0)
+#  define MYUART_PMUX_VAL (PORTMUX_USART0_DEFAULT_gc)
+# elif (UARTTX == A4)
+#  define UART_NAME "A4"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTA
+#  define MYUART_TXPIN (1<<PORT4)
+#  define MYUART_PMUX_VAL (PORTMUX_USART0_ALT1_gc)
+# elif (UARTTX == B0)
+#  define UART_NAME "B0"
+#  ifndef USART3
+#   error Pin on USART3, but no USART3 exists
+#  endif
+#  define MYUART USART3
+#  define MYUART_TXPORT VPORTB
+#  define MYUART_TXPIN (1<<PORT0)
+#  define MYUART_PMUX_VAL (PORTMUX_USART3_DEFAULT_gc)
+# elif (UARTTX == B4)
+#  define UART_NAME "B4"
+#  ifndef USART3
+#   error Pin on USART3, but no USART3 exists
+#  endif
+#  define MYUART USART3
+#  define MYUART_TXPORT VPORTB
+#  define MYUART_TXPIN (1<<PORT4)
+#  define MYUART_PMUX_VAL (PORTMUX_USART3_ALT1_gc)
+# elif (UARTTX == C0)
+#  define UART_NAME "C0"
+#  ifndef USART1
+#   error Pin on USART1, but no USART1 exists
+#  endif
+#  define MYUART USART1
+#  define MYUART_TXPORT VPORTC
+#  define MYUART_TXPIN (1<<PORT0)
+#  define MYUART_PMUX_VAL (PORTMUX_USART1_DEFAULT_gc)
+# elif (UARTTX == C4)
+#  define UART_NAME "C4"
+#  ifndef USART1
+#   error Pin on USART1, but no USART1 exists
+#  endif
+#  define MYUART USART1
+#  define MYUART_TXPORT VPORTC
+#  define MYUART_TXPIN (1<<PORT4)
+#  define MYUART_PMUX_VAL (PORTMUX_USART1_ALT1_gc)
+# elif (UARTTX == F0)
+#  define UART_NAME "F0"
+#  ifndef USART2
+#   error Pin on USART2, but no USART2 exists
+#  endif
+#  define MYUART USART2
+#  define MYUART_TXPORT VPORTF
+#  define MYUART_TXPIN (1<<PORT0)
+#  define MYUART_PMUX_VAL (PORTMUX_USART2_DEFAULT_gc)
+# elif (UARTTX == F4)
+#  define UART_NAME "F4"
+#  ifndef USART2
+#   error Pin on USART2, but no USART2 exists
+#  endif
+#  define MYUART USART2
+#  define MYUART_TXPORT VPORTF
+#  define MYUART_TXPIN (1<<PORT4)
+#  define MYUART_PMUX_VAL (PORTMUX_USART2_ALT1_gc)
+# else
+#  pragma GCC diagnostic warning "-Wfatal-errors"
+#  pragma GCC error "Invalid UARTTX pin for chip"
+# endif
+#endif  // ATmega4809
+
+/*
+ * 8pin Tiny0 and Tiny1
+ */
+#if defined(__AVR_ATtiny402__) || defined(__AVR_ATtiny202__) || \
+    defined(__AVR_ATtiny412__) || defined(__AVR_ATtiny212__)
+#define MYPMUX_REG PORTMUX.CTRLB
+# if (UARTTX == A6)
+#  define UART_NAME "A6"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTA
+#  define MYUART_TXPIN (1<<PORT6)
+#  define MYUART_PMUX_VAL 0
+# elif (UARTTX == A1)
+#  define UART_NAME "A1"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTA
+#  define MYUART_TXPIN (1<<PORT1)
+#  define MYUART_PMUX_VAL (USART_ALTPMUX)
+# else
+#  pragma GCC diagnostic warning "-Wfatal-errors"
+#  pragma GCC error "Invalid UARTTX pin for chip"
+# endif
+#endif // Tiny402/etc
+
+/*
+ *  14, 20, and 24 pin  Tiny0, Tiny1
+ *   The 14, 20, and 24pin packages all conveniently have the UART on the
+ *   same port pins, and the same pinmux structure!
+ */
+#if defined(__AVR_ATtiny1614__) || defined(__AVR_ATtiny1604__) ||       \
+    defined(__AVR_ATtiny814__)  || defined(__AVR_ATtiny804__) ||        \
+    defined(__AVR_ATtiny1606__) || defined(__AVR_ATtiny806__) ||        \
+    defined(__AVR_ATtiny406__) || defined(__AVR_ATtiny3216__) ||        \
+    defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny416__) || \
+    defined(__AVR_ATtiny1617__) || defined(__AVR_ATtiny3217__) || \
+    defined(__AVR_ATtiny1607__) || defined(__AVR_ATtiny817__)
+#define MYPMUX_REG PORTMUX.CTRLB
+# if (UARTTX == B2)
+#  define UART_NAME "B2"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTB
+#  define MYUART_TXPIN (1<<PORT2)
+#  define MYUART_PMUX_VAL 0
+# elif (UARTTX == A1)
+#  define UART_NAME "A1"
+#  ifndef USART0
+#   error Pin on USART0, but no USART0 exists
+#  endif
+#  define MYUART USART0
+#  define MYUART_TXPORT VPORTA
+#  define MYUART_TXPIN (1<<PORT1)
+#  define MYUART_PMUX_VAL (USART_ALTPMUX)
+# else
+#  pragma GCC diagnostic warning "-Wfatal-errors"
+#  pragma GCC error "Invalid UARTTX pin for chip"
+# endif
+#endif
+
+#ifndef MYUART
+# warning No UARTTX pin specified.
+#endif
+
+#ifdef RS485
+#include "pins_rs485.h"
+#endif

+ 1266 - 0
optiboot/pins_rs485.h

@@ -0,0 +1,1266 @@
+#ifdef __AVR_XMEGA__
+#define _mkPort(a) V##a
+#else
+#define _mkPort(a) a
+#endif
+
+#define PIN_INVERTED 0x8000
+#define A0_INV (PIN_INVERTED + A0)
+#define A1_INV (PIN_INVERTED + A1)
+#define A2_INV (PIN_INVERTED + A2)
+#define A3_INV (PIN_INVERTED + A3)
+#define A4_INV (PIN_INVERTED + A4)
+#define A5_INV (PIN_INVERTED + A5)
+#define A6_INV (PIN_INVERTED + A6)
+#define A7_INV (PIN_INVERTED + A7)
+#define B0_INV (PIN_INVERTED + B0)
+#define B1_INV (PIN_INVERTED + B1)
+#define B2_INV (PIN_INVERTED + B2)
+#define B3_INV (PIN_INVERTED + B3)
+#define B4_INV (PIN_INVERTED + B4)
+#define B5_INV (PIN_INVERTED + B5)
+#define B6_INV (PIN_INVERTED + B6)
+#define B7_INV (PIN_INVERTED + B7)
+#define C0_INV (PIN_INVERTED + C0)
+#define C1_INV (PIN_INVERTED + C1)
+#define C2_INV (PIN_INVERTED + C2)
+#define C3_INV (PIN_INVERTED + C3)
+#define C4_INV (PIN_INVERTED + C4)
+#define C5_INV (PIN_INVERTED + C5)
+#define C6_INV (PIN_INVERTED + C6)
+#define C7_INV (PIN_INVERTED + C7)
+#define D0_INV (PIN_INVERTED + D0)
+#define D1_INV (PIN_INVERTED + D1)
+#define D2_INV (PIN_INVERTED + D2)
+#define D3_INV (PIN_INVERTED + D3)
+#define D4_INV (PIN_INVERTED + D4)
+#define D5_INV (PIN_INVERTED + D5)
+#define D6_INV (PIN_INVERTED + D6)
+#define D7_INV (PIN_INVERTED + D7)
+#define E0_INV (PIN_INVERTED + E0)
+#define E1_INV (PIN_INVERTED + E1)
+#define E2_INV (PIN_INVERTED + E2)
+#define E3_INV (PIN_INVERTED + E3)
+#define E4_INV (PIN_INVERTED + E4)
+#define E5_INV (PIN_INVERTED + E5)
+#define E6_INV (PIN_INVERTED + E6)
+#define E7_INV (PIN_INVERTED + E7)
+#define F0_INV (PIN_INVERTED + F0)
+#define F1_INV (PIN_INVERTED + F1)
+#define F2_INV (PIN_INVERTED + F2)
+#define F3_INV (PIN_INVERTED + F3)
+#define F4_INV (PIN_INVERTED + F4)
+#define F5_INV (PIN_INVERTED + F5)
+#define F6_INV (PIN_INVERTED + F6)
+#define F7_INV (PIN_INVERTED + F7)
+#define G0_INV (PIN_INVERTED + G0)
+#define G1_INV (PIN_INVERTED + G1)
+#define G2_INV (PIN_INVERTED + G2)
+#define G3_INV (PIN_INVERTED + G3)
+#define G4_INV (PIN_INVERTED + G4)
+#define G5_INV (PIN_INVERTED + G5)
+#define G6_INV (PIN_INVERTED + G6)
+#define G7_INV (PIN_INVERTED + G7)
+#define H0_INV (PIN_INVERTED + H0)
+#define H1_INV (PIN_INVERTED + H1)
+#define H2_INV (PIN_INVERTED + H2)
+#define H3_INV (PIN_INVERTED + H3)
+#define H4_INV (PIN_INVERTED + H4)
+#define H5_INV (PIN_INVERTED + H5)
+#define H6_INV (PIN_INVERTED + H6)
+#define H7_INV (PIN_INVERTED + H7)
+#define J0_INV (PIN_INVERTED + J0)
+#define J1_INV (PIN_INVERTED + J1)
+#define J2_INV (PIN_INVERTED + J2)
+#define J3_INV (PIN_INVERTED + J3)
+#define J4_INV (PIN_INVERTED + J4)
+#define J5_INV (PIN_INVERTED + J5)
+#define J6_INV (PIN_INVERTED + J6)
+#define J7_INV (PIN_INVERTED + J7)
+#define K0_INV (PIN_INVERTED + K0)
+#define K1_INV (PIN_INVERTED + K1)
+#define K2_INV (PIN_INVERTED + K2)
+#define K3_INV (PIN_INVERTED + K3)
+#define K4_INV (PIN_INVERTED + K4)
+#define K5_INV (PIN_INVERTED + K5)
+#define K6_INV (PIN_INVERTED + K6)
+#define K7_INV (PIN_INVERTED + K7)
+#define L0_INV (PIN_INVERTED + L0)
+#define L1_INV (PIN_INVERTED + L1)
+#define L2_INV (PIN_INVERTED + L2)
+#define L3_INV (PIN_INVERTED + L3)
+#define L4_INV (PIN_INVERTED + L4)
+#define L5_INV (PIN_INVERTED + L5)
+#define L6_INV (PIN_INVERTED + L6)
+#define L7_INV (PIN_INVERTED + L7)
+
+#if RS485 == B0
+#define RS485_NAME "B0"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN0
+#elif RS485 == B1
+#define RS485_NAME "B1"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN1
+#elif RS485 == B2
+#define RS485_NAME "B2"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN2
+#elif RS485 == B3
+#define RS485_NAME "B3"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN3
+#elif RS485 == B4
+#define RS485_NAME "B4"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN4
+#elif RS485 == B5
+#define RS485_NAME "B5"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN5
+#elif RS485 == B6
+#define RS485_NAME "B6"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN6
+#elif RS485 == B7
+#define RS485_NAME "B7"
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN7
+
+#elif RS485 == C0
+#define RS485_NAME "C0"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN0
+#elif RS485 == C1
+#define RS485_NAME "C1"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN1
+#elif RS485 == C2
+#define RS485_NAME "C2"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN2
+#elif RS485 == C3
+#define RS485_NAME "C3"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN3
+#elif RS485 == C4
+#define RS485_NAME "C4"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN4
+#elif RS485 == C5
+#define RS485_NAME "C5"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN5
+#elif RS485 == C6
+#define RS485_NAME "C6"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN6
+#elif RS485 == C7
+#define RS485_NAME "C7"
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN7
+
+#elif RS485 == D0
+#define RS485_NAME "D0"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN0
+#elif RS485 == D1
+#define RS485_NAME "D1"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN1
+#elif RS485 == D2
+#define RS485_NAME "D2"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN2
+#elif RS485 == D3
+#define RS485_NAME "D3"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN3
+#elif RS485 == D4
+#define RS485_NAME "D4"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN4
+#elif RS485 == D5
+#define RS485_NAME "D5"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN5
+#elif RS485 == D6
+#define RS485_NAME "D6"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN6
+#elif RS485 == D7
+#define RS485_NAME "D7"
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN7
+
+#elif RS485 == E0
+#define RS485_NAME "E0"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN0
+#elif RS485 == E1
+#define RS485_NAME "E1"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN1
+#elif RS485 == E2
+#define RS485_NAME "E2"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN2
+#elif RS485 == E3
+#define RS485_NAME "E3"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN3
+#elif RS485 == E4
+#define RS485_NAME "E4"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN4
+#elif RS485 == E5
+#define RS485_NAME "E5"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN5
+#elif RS485 == E6
+#define RS485_NAME "E6"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN6
+#elif RS485 == E7
+#define RS485_NAME "E7"
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN7
+
+#elif RS485 == F0
+#define RS485_NAME "F0"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN0
+#elif RS485 == F1
+#define RS485_NAME "F1"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN1
+#elif RS485 == F2
+#define RS485_NAME "F2"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN2
+#elif RS485 == F3
+#define RS485_NAME "F3"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN3
+#elif RS485 == F4
+#define RS485_NAME "F4"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN4
+#elif RS485 == F5
+#define RS485_NAME "F5"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN5
+#elif RS485 == F6
+#define RS485_NAME "F6"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN6
+#elif RS485 == F7
+#define RS485_NAME "F7"
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN7
+
+#elif RS485 == G0
+#define RS485_NAME "G0"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN0
+#elif RS485 == G1
+#define RS485_NAME "G1"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN1
+#elif RS485 == G2
+#define RS485_NAME "G2"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN2
+#elif RS485 == G3
+#define RS485_NAME "G3"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN3
+#elif RS485 == G4
+#define RS485_NAME "G4"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN4
+#elif RS485 == G5
+#define RS485_NAME "G5"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN5
+#elif RS485 == G6
+#define RS485_NAME "G6"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN6
+#elif RS485 == G7
+#define RS485_NAME "G7"
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN7
+
+#elif RS485 == H0
+#define RS485_NAME "H0"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN0
+#elif RS485 == H1
+#define RS485_NAME "H1"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN1
+#elif RS485 == H2
+#define RS485_NAME "H2"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN2
+#elif RS485 == H3
+#define RS485_NAME "H3"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN3
+#elif RS485 == H4
+#define RS485_NAME "H4"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN4
+#elif RS485 == H5
+#define RS485_NAME "H5"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN5
+#elif RS485 == H6
+#define RS485_NAME "H6"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN6
+#elif RS485 == H7
+#define RS485_NAME "H7"
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN7
+
+#elif RS485 == J0
+#define RS485_NAME "J0"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN0
+#elif RS485 == J1
+#define RS485_NAME "J1"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN1
+#elif RS485 == J2
+#define RS485_NAME "J2"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN2
+#elif RS485 == J3
+#define RS485_NAME "J3"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN3
+#elif RS485 == J4
+#define RS485_NAME "J4"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN4
+#elif RS485 == J5
+#define RS485_NAME "J5"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN5
+#elif RS485 == J6
+#define RS485_NAME "J6"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN6
+#elif RS485 == J7
+#define RS485_NAME "J7"
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN7
+
+#elif RS485 == K0
+#define RS485_NAME "K0"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN0
+#elif RS485 == K1
+#define RS485_NAME "K1"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN1
+#elif RS485 == K2
+#define RS485_NAME "K2"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN2
+#elif RS485 == K3
+#define RS485_NAME "K3"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN3
+#elif RS485 == K4
+#define RS485_NAME "K4"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN4
+#elif RS485 == K5
+#define RS485_NAME "K5"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN5
+#elif RS485 == K6
+#define RS485_NAME "K6"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN6
+#elif RS485 == K7
+#define RS485_NAME "K7"
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN7
+
+#elif RS485 == L0
+#define RS485_NAME "L0"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN0
+#elif RS485 == L1
+#define RS485_NAME "L1"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN1
+#elif RS485 == L2
+#define RS485_NAME "L2"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN2
+#elif RS485 == L3
+#define RS485_NAME "L3"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN3
+#elif RS485 == L4
+#define RS485_NAME "L4"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN4
+#elif RS485 == L5
+#define RS485_NAME "L5"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN5
+#elif RS485 == L6
+#define RS485_NAME "L6"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN6
+#elif RS485 == L7
+#define RS485_NAME "L7"
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN7
+
+#elif RS485 == A0
+#define RS485_NAME "A0"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN0
+#elif RS485 == A1
+#define RS485_NAME "A1"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN1
+#elif RS485 == A2
+#define RS485_NAME "A2"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN2
+#elif RS485 == A3
+#define RS485_NAME "A3"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN3
+#elif RS485 == A4
+#define RS485_NAME "A4"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN4
+#elif RS485 == A5
+#define RS485_NAME "A5"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN5
+#elif RS485 == A6
+#define RS485_NAME "A6"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN6
+#elif RS485 == A7
+#define RS485_NAME "A7"
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN7
+#elif RS485 == B0_INV
+#define RS485_NAME "B0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN0
+#elif RS485 == B1_INV
+#define RS485_NAME "B1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN1
+#elif RS485 == B2_INV
+#define RS485_NAME "B2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN2
+#elif RS485 == B3_INV
+#define RS485_NAME "B3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN3
+#elif RS485 == B4_INV
+#define RS485_NAME "B4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN4
+#elif RS485 == B5_INV
+#define RS485_NAME "B5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN5
+#elif RS485 == B6_INV
+#define RS485_NAME "B6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN6
+#elif RS485 == B7_INV
+#define RS485_NAME "B7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRB
+#define RS485_PORT    _mkPort(PORTB)
+#define RS485_PIN     PINB
+#define RS485_BIT     PIN7
+
+#elif RS485 == C0_INV
+#define RS485_NAME "C0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN0
+#elif RS485 == C1_INV
+#define RS485_NAME "C1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN1
+#elif RS485 == C2_INV
+#define RS485_NAME "C2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN2
+#elif RS485 == C3_INV
+#define RS485_NAME "C3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN3
+#elif RS485 == C4_INV
+#define RS485_NAME "C4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN4
+#elif RS485 == C5_INV
+#define RS485_NAME "C5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN5
+#elif RS485 == C6_INV
+#define RS485_NAME "C6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN6
+#elif RS485 == C7_INV
+#define RS485_NAME "C7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRC
+#define RS485_PORT    _mkPort(PORTC)
+#define RS485_PIN     PINC
+#define RS485_BIT     PIN7
+
+#elif RS485 == D0_INV
+#define RS485_NAME "D0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN0
+#elif RS485 == D1_INV
+#define RS485_NAME "D1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN1
+#elif RS485 == D2_INV
+#define RS485_NAME "D2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN2
+#elif RS485 == D3_INV
+#define RS485_NAME "D3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN3
+#elif RS485 == D4_INV
+#define RS485_NAME "D4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN4
+#elif RS485 == D5_INV
+#define RS485_NAME "D5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN5
+#elif RS485 == D6_INV
+#define RS485_NAME "D6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN6
+#elif RS485 == D7_INV
+#define RS485_NAME "D7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRD
+#define RS485_PORT    _mkPort(PORTD)
+#define RS485_PIN     PIND
+#define RS485_BIT     PIN7
+
+#elif RS485 == E0_INV
+#define RS485_NAME "E0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN0
+#elif RS485 == E1_INV
+#define RS485_NAME "E1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN1
+#elif RS485 == E2_INV
+#define RS485_NAME "E2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN2
+#elif RS485 == E3_INV
+#define RS485_NAME "E3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN3
+#elif RS485 == E4_INV
+#define RS485_NAME "E4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN4
+#elif RS485 == E5_INV
+#define RS485_NAME "E5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN5
+#elif RS485 == E6_INV
+#define RS485_NAME "E6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN6
+#elif RS485 == E7_INV
+#define RS485_NAME "E7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRE
+#define RS485_PORT    _mkPort(PORTE)
+#define RS485_PIN     PINE
+#define RS485_BIT     PIN7
+
+#elif RS485 == F0_INV
+#define RS485_NAME "F0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN0
+#elif RS485 == F1_INV
+#define RS485_NAME "F1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN1
+#elif RS485 == F2_INV
+#define RS485_NAME "F2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN2
+#elif RS485 == F3_INV
+#define RS485_NAME "F3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN3
+#elif RS485 == F4_INV
+#define RS485_NAME "F4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN4
+#elif RS485 == F5_INV
+#define RS485_NAME "F5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN5
+#elif RS485 == F6_INV
+#define RS485_NAME "F6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN6
+#elif RS485 == F7_INV
+#define RS485_NAME "F7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRF
+#define RS485_PORT    _mkPort(PORTF)
+#define RS485_PIN     PINF
+#define RS485_BIT     PIN7
+
+#elif RS485 == G0_INV
+#define RS485_NAME "G0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN0
+#elif RS485 == G1_INV
+#define RS485_NAME "G1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN1
+#elif RS485 == G2_INV
+#define RS485_NAME "G2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN2
+#elif RS485 == G3_INV
+#define RS485_NAME "G3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN3
+#elif RS485 == G4_INV
+#define RS485_NAME "G4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN4
+#elif RS485 == G5_INV
+#define RS485_NAME "G5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN5
+#elif RS485 == G6_INV
+#define RS485_NAME "G6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN6
+#elif RS485 == G7_INV
+#define RS485_NAME "G7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRG
+#define RS485_PORT    _mkPort(PORTG)
+#define RS485_PIN     PING
+#define RS485_BIT     PIN7
+
+#elif RS485 == H0_INV
+#define RS485_NAME "H0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN0
+#elif RS485 == H1_INV
+#define RS485_NAME "H1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN1
+#elif RS485 == H2_INV
+#define RS485_NAME "H2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN2
+#elif RS485 == H3_INV
+#define RS485_NAME "H3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN3
+#elif RS485 == H4_INV
+#define RS485_NAME "H4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN4
+#elif RS485 == H5_INV
+#define RS485_NAME "H5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN5
+#elif RS485 == H6_INV
+#define RS485_NAME "H6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN6
+#elif RS485 == H7_INV
+#define RS485_NAME "H7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRH
+#define RS485_PORT    _mkPort(PORTH)
+#define RS485_PIN     PINH
+#define RS485_BIT     PIN7
+
+#elif RS485 == J0_INV
+#define RS485_NAME "J0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN0
+#elif RS485 == J1_INV
+#define RS485_NAME "J1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN1
+#elif RS485 == J2_INV
+#define RS485_NAME "J2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN2
+#elif RS485 == J3_INV
+#define RS485_NAME "J3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN3
+#elif RS485 == J4_INV
+#define RS485_NAME "J4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN4
+#elif RS485 == J5_INV
+#define RS485_NAME "J5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN5
+#elif RS485 == J6_INV
+#define RS485_NAME "J6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN6
+#elif RS485 == J7_INV
+#define RS485_NAME "J7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRJ
+#define RS485_PORT    _mkPort(PORTJ)
+#define RS485_PIN     PINJ
+#define RS485_BIT     PIN7
+
+#elif RS485 == K0_INV
+#define RS485_NAME "K0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN0
+#elif RS485 == K1_INV
+#define RS485_NAME "K1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN1
+#elif RS485 == K2_INV
+#define RS485_NAME "K2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN2
+#elif RS485 == K3_INV
+#define RS485_NAME "K3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN3
+#elif RS485 == K4_INV
+#define RS485_NAME "K4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN4
+#elif RS485 == K5_INV
+#define RS485_NAME "K5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN5
+#elif RS485 == K6_INV
+#define RS485_NAME "K6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN6
+#elif RS485 == K7_INV
+#define RS485_NAME "K7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRK
+#define RS485_PORT    _mkPort(PORTK)
+#define RS485_PIN     PINK
+#define RS485_BIT     PIN7
+
+#elif RS485 == L0_INV
+#define RS485_NAME "L0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN0
+#elif RS485 == L1_INV
+#define RS485_NAME "L1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN1
+#elif RS485 == L2_INV
+#define RS485_NAME "L2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN2
+#elif RS485 == L3_INV
+#define RS485_NAME "L3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN3
+#elif RS485 == L4_INV
+#define RS485_NAME "L4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN4
+#elif RS485 == L5_INV
+#define RS485_NAME "L5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN5
+#elif RS485 == L6_INV
+#define RS485_NAME "L6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN6
+#elif RS485 == L7_INV
+#define RS485_NAME "L7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRL
+#define RS485_PORT    _mkPort(PORTL)
+#define RS485_PIN     PINL
+#define RS485_BIT     PIN7
+
+#elif RS485 == A0_INV
+#define RS485_NAME "A0_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN0
+#elif RS485 == A1_INV
+#define RS485_NAME "A1_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN1
+#elif RS485 == A2_INV
+#define RS485_NAME "A2_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN2
+#elif RS485 == A3_INV
+#define RS485_NAME "A3_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN3
+#elif RS485 == A4_INV
+#define RS485_NAME "A4_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN4
+#elif RS485 == A5_INV
+#define RS485_NAME "A5_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN5
+#elif RS485 == A6_INV
+#define RS485_NAME "A6_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN6
+#elif RS485 == A7_INV
+#define RS485_NAME "A7_INV"
+#define RS485_INVERT
+#define RS485_DDR     DDRA
+#define RS485_PORT    _mkPort(PORTA)
+#define RS485_PIN     PINA
+#define RS485_BIT     PIN7
+#else
+#error -------------------------------------------
+#error Unrecognized RS485 name.  Should be like "B5"
+#error or "B5_INV" for active high
+#error -------------------------------------------
+#endif

+ 831 - 0
optiboot/pins_softuart.h

@@ -0,0 +1,831 @@
+#undef UART_PORT
+#undef UART_PIN
+#undef UART_DDR
+#undef UART_TX_BIT
+#undef UART_RX_BIT
+
+#if SOFTTX == B0
+#define SOFTTX_NAME "B0"
+#define UART_DDR     DDRB
+#define UART_PORT    PORTB
+#define UART_TX_BIT  PINB0
+#elif SOFTTX == B1
+#define SOFTTX_NAME "B1"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB1
+#elif SOFTTX == B2
+#define SOFTTX_NAME "B2"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB2
+#elif SOFTTX == B3
+#define SOFTTX_NAME "B3"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB3
+#elif SOFTTX == B4
+#define SOFTTX_NAME "B4"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB4
+#elif SOFTTX == B5
+#define SOFTTX_NAME "B5"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB5
+#elif SOFTTX == B6
+#define SOFTTX_NAME "B6"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB6
+#elif SOFTTX == B7
+#define SOFTTX_NAME "B7"
+#define UART_DDR     DDRB
+#define UART_PORT      PORTB
+#define UART_TX_BIT    PINB7
+
+#elif SOFTTX == C0
+#define SOFTTX_NAME "C0"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC0
+#elif SOFTTX == C1
+#define SOFTTX_NAME "C1"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC1
+#elif SOFTTX == C2
+#define SOFTTX_NAME "C2"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC2
+#elif SOFTTX == C3
+#define SOFTTX_NAME "C3"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC3
+#elif SOFTTX == C4
+#define SOFTTX_NAME "C4"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC4
+#elif SOFTTX == C5
+#define SOFTTX_NAME "C5"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC5
+#elif SOFTTX == C6
+#define SOFTTX_NAME "C6"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC6
+#elif SOFTTX == C7
+#define SOFTTX_NAME "C7"
+#define UART_DDR     DDRC
+#define UART_PORT      PORTC
+#define UART_TX_BIT    PINC7
+
+#elif SOFTTX == D0
+#define SOFTTX_NAME "D0"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND0
+#elif SOFTTX == D1
+#define SOFTTX_NAME "D1"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND1
+#elif SOFTTX == D2
+#define SOFTTX_NAME "D2"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND2
+#elif SOFTTX == D3
+#define SOFTTX_NAME "D3"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND3
+#elif SOFTTX == D4
+#define SOFTTX_NAME "D4"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND4
+#elif SOFTTX == D5
+#define SOFTTX_NAME "D5"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND5
+#elif SOFTTX == D6
+#define SOFTTX_NAME "D6"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND6
+#elif SOFTTX == D7
+#define SOFTTX_NAME "D7"
+#define UART_DDR     DDRD
+#define UART_PORT      PORTD
+#define UART_TX_BIT    PIND7
+
+#elif SOFTTX == E0
+#define SOFTTX_NAME "E0"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE0
+#elif SOFTTX == E1
+#define SOFTTX_NAME "E1"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE1
+#elif SOFTTX == E2
+#define SOFTTX_NAME "E2"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE2
+#elif SOFTTX == E3
+#define SOFTTX_NAME "E3"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE3
+#elif SOFTTX == E4
+#define SOFTTX_NAME "E4"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE4
+#elif SOFTTX == E5
+#define SOFTTX_NAME "E5"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE5
+#elif SOFTTX == E6
+#define SOFTTX_NAME "E6"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE6
+#elif SOFTTX == E7
+#define SOFTTX_NAME "E7"
+#define UART_DDR     DDRE
+#define UART_PORT      PORTE
+#define UART_TX_BIT    PINE7
+
+#elif SOFTTX == F0
+#define SOFTTX_NAME "F0"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF0
+#elif SOFTTX == F1
+#define SOFTTX_NAME "F1"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF1
+#elif SOFTTX == F2
+#define SOFTTX_NAME "F2"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF2
+#elif SOFTTX == F3
+#define SOFTTX_NAME "F3"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF3
+#elif SOFTTX == F4
+#define SOFTTX_NAME "F4"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF4
+#elif SOFTTX == F5
+#define SOFTTX_NAME "F5"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF5
+#elif SOFTTX == F6
+#define SOFTTX_NAME "F6"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF6
+#elif SOFTTX == F7
+#define SOFTTX_NAME "F7"
+#define UART_DDR     DDRF
+#define UART_PORT      PORTF
+#define UART_TX_BIT    PINF7
+
+#elif SOFTTX == G0
+#define SOFTTX_NAME "G0"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING0
+#elif SOFTTX == G1
+#define SOFTTX_NAME "G1"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING1
+#elif SOFTTX == G2
+#define SOFTTX_NAME "G2"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING2
+#elif SOFTTX == G3
+#define SOFTTX_NAME "G3"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING3
+#elif SOFTTX == G4
+#define SOFTTX_NAME "G4"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING4
+#elif SOFTTX == G5
+#define SOFTTX_NAME "G5"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING5
+#elif SOFTTX == G6
+#define SOFTTX_NAME "G6"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING6
+#elif SOFTTX == G7
+#define SOFTTX_NAME "G7"
+#define UART_DDR     DDRG
+#define UART_PORT      PORTG
+#define UART_TX_BIT    PING7
+
+#elif SOFTTX == H0
+#define SOFTTX_NAME "H0"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH0
+#elif SOFTTX == H1
+#define SOFTTX_NAME "H1"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH1
+#elif SOFTTX == H2
+#define SOFTTX_NAME "H2"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH2
+#elif SOFTTX == H3
+#define SOFTTX_NAME "H3"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH3
+#elif SOFTTX == H4
+#define SOFTTX_NAME "H4"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH4
+#elif SOFTTX == H5
+#define SOFTTX_NAME "H5"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH5
+#elif SOFTTX == H6
+#define SOFTTX_NAME "H6"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH6
+#elif SOFTTX == H7
+#define SOFTTX_NAME "H7"
+#define UART_DDR     DDRH
+#define UART_PORT      PORTH
+#define UART_TX_BIT    PINH7
+
+#elif SOFTTX == J0
+#define SOFTTX_NAME "J0"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ0
+#elif SOFTTX == J1
+#define SOFTTX_NAME "J1"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ1
+#elif SOFTTX == J2
+#define SOFTTX_NAME "J2"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ2
+#elif SOFTTX == J3
+#define SOFTTX_NAME "J3"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ3
+#elif SOFTTX == J4
+#define SOFTTX_NAME "J4"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ4
+#elif SOFTTX == J5
+#define SOFTTX_NAME "J5"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ5
+#elif SOFTTX == J6
+#define SOFTTX_NAME "J6"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ6
+#elif SOFTTX == J7
+#define SOFTTX_NAME "J7"
+#define UART_DDR     DDRJ
+#define UART_PORT      PORTJ
+#define UART_TX_BIT    PINJ7
+
+#elif SOFTTX == K0
+#define SOFTTX_NAME "K0"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK0
+#elif SOFTTX == K1
+#define SOFTTX_NAME "K1"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK1
+#elif SOFTTX == K2
+#define SOFTTX_NAME "K2"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK2
+#elif SOFTTX == K3
+#define SOFTTX_NAME "K3"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK3
+#elif SOFTTX == K4
+#define SOFTTX_NAME "K4"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK4
+#elif SOFTTX == K5
+#define SOFTTX_NAME "K5"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK5
+#elif SOFTTX == K6
+#define SOFTTX_NAME "K6"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK6
+#elif SOFTTX == K7
+#define SOFTTX_NAME "K7"
+#define UART_DDR     DDRK
+#define UART_PORT      PORTK
+#define UART_TX_BIT    PINK7
+
+#elif SOFTTX == L0
+#define SOFTTX_NAME "L0"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL0
+#elif SOFTTX == L1
+#define SOFTTX_NAME "L1"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL1
+#elif SOFTTX == L2
+#define SOFTTX_NAME "L2"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL2
+#elif SOFTTX == L3
+#define SOFTTX_NAME "L3"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL3
+#elif SOFTTX == L4
+#define SOFTTX_NAME "L4"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL4
+#elif SOFTTX == L5
+#define SOFTTX_NAME "L5"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL5
+#elif SOFTTX == L6
+#define SOFTTX_NAME "L6"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL6
+#elif SOFTTX == L7
+#define SOFTTX_NAME "L7"
+#define UART_DDR     DDRL
+#define UART_PORT      PORTL
+#define UART_TX_BIT    PINL7
+
+#elif SOFTTX == A0
+#define SOFTTX_NAME "A0"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA0
+#elif SOFTTX == A1
+#define SOFTTX_NAME "A1"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA1
+#elif SOFTTX == A2
+#define SOFTTX_NAME "A2"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA2
+#elif SOFTTX == A3
+#define SOFTTX_NAME "A3"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA3
+#elif SOFTTX == A4
+#define SOFTTX_NAME "A4"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA4
+#elif SOFTTX == A5
+#define SOFTTX_NAME "A5"
+#define UART_DDR     DDRA
+#define UART_PORT      PORTA
+#define UART_TX_BIT    PINA5
+#elif SOFTTX == A6
+#define SOFTTX_NAME "A6"
+#define UART_DDR     DDRA
+#define UART_PORT    PORTA
+#define UART_TX_BIT  PINA6
+#elif SOFTTX == A7
+#define SOFTTX_NAME "A7"
+#define UART_DDR     DDRA
+#define UART_PORT    PORTA
+#define UART_TX_BIT  PINA7
+#else
+#error -------------------------------------------
+#error Unrecognized SOFTTX name.  Should be like "B5"
+#error -------------------------------------------
+#endif
+
+
+#if SOFTRX == B0
+#define SOFTRX_NAME "B0"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB0
+#elif SOFTRX == B1
+#define SOFTRX_NAME "B1"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB1
+#elif SOFTRX == B2
+#define SOFTRX_NAME "B2"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB2
+#elif SOFTRX == B3
+#define SOFTRX_NAME "B3"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB3
+#elif SOFTRX == B4
+#define SOFTRX_NAME "B4"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB4
+#elif SOFTRX == B5
+#define SOFTRX_NAME "B5"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB5
+#elif SOFTRX == B6
+#define SOFTRX_NAME "B6"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB6
+#elif SOFTRX == B7
+#define SOFTRX_NAME "B7"
+#define UART_PIN       PINB
+#define UART_RX_BIT    PINB7
+
+#elif SOFTRX == C0
+#define SOFTRX_NAME "C0"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC0
+#elif SOFTRX == C1
+#define SOFTRX_NAME "C1"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC1
+#elif SOFTRX == C2
+#define SOFTRX_NAME "C2"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC2
+#elif SOFTRX == C3
+#define SOFTRX_NAME "C3"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC3
+#elif SOFTRX == C4
+#define SOFTRX_NAME "C4"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC4
+#elif SOFTRX == C5
+#define SOFTRX_NAME "C5"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC5
+#elif SOFTRX == C6
+#define SOFTRX_NAME "C6"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC6
+#elif SOFTRX == C7
+#define SOFTRX_NAME "C7"
+#define UART_PIN       PINC
+#define UART_RX_BIT    PINC7
+
+#elif SOFTRX == D0
+#define SOFTRX_NAME "D0"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND0
+#elif SOFTRX == D1
+#define SOFTRX_NAME "D1"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND1
+#elif SOFTRX == D2
+#define SOFTRX_NAME "D2"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND2
+#elif SOFTRX == D3
+#define SOFTRX_NAME "D3"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND3
+#elif SOFTRX == D4
+#define SOFTRX_NAME "D4"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND4
+#elif SOFTRX == D5
+#define SOFTRX_NAME "D5"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND5
+#elif SOFTRX == D6
+#define SOFTRX_NAME "D6"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND6
+#elif SOFTRX == D7
+#define SOFTRX_NAME "D7"
+#define UART_PIN       PIND
+#define UART_RX_BIT    PIND7
+
+#elif SOFTRX == E0
+#define SOFTRX_NAME "E0"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE0
+#elif SOFTRX == E1
+#define SOFTRX_NAME "E1"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE1
+#elif SOFTRX == E2
+#define SOFTRX_NAME "E2"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE2
+#elif SOFTRX == E3
+#define SOFTRX_NAME "E3"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE3
+#elif SOFTRX == E4
+#define SOFTRX_NAME "E4"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE4
+#elif SOFTRX == E5
+#define SOFTRX_NAME "E5"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE5
+#elif SOFTRX == E6
+#define SOFTRX_NAME "E6"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE6
+#elif SOFTRX == E7
+#define SOFTRX_NAME "E7"
+#define UART_PIN       PINE
+#define UART_RX_BIT    PINE7
+
+#elif SOFTRX == F0
+#define SOFTRX_NAME "F0"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF0
+#elif SOFTRX == F1
+#define SOFTRX_NAME "F1"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF1
+#elif SOFTRX == F2
+#define SOFTRX_NAME "F2"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF2
+#elif SOFTRX == F3
+#define SOFTRX_NAME "F3"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF3
+#elif SOFTRX == F4
+#define SOFTRX_NAME "F4"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF4
+#elif SOFTRX == F5
+#define SOFTRX_NAME "F5"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF5
+#elif SOFTRX == F6
+#define SOFTRX_NAME "F6"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF6
+#elif SOFTRX == F7
+#define SOFTRX_NAME "F7"
+#define UART_PIN       PINF
+#define UART_RX_BIT    PINF7
+
+#elif SOFTRX == G0
+#define SOFTRX_NAME "G0"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING0
+#elif SOFTRX == G1
+#define SOFTRX_NAME "G1"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING1
+#elif SOFTRX == G2
+#define SOFTRX_NAME "G2"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING2
+#elif SOFTRX == G3
+#define SOFTRX_NAME "G3"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING3
+#elif SOFTRX == G4
+#define SOFTRX_NAME "G4"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING4
+#elif SOFTRX == G5
+#define SOFTRX_NAME "G5"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING5
+#elif SOFTRX == G6
+#define SOFTRX_NAME "G6"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING6
+#elif SOFTRX == G7
+#define SOFTRX_NAME "G7"
+#define UART_PIN       PING
+#define UART_RX_BIT    PING7
+
+#elif SOFTRX == H0
+#define SOFTRX_NAME "H0"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH0
+#elif SOFTRX == H1
+#define SOFTRX_NAME "H1"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH1
+#elif SOFTRX == H2
+#define SOFTRX_NAME "H2"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH2
+#elif SOFTRX == H3
+#define SOFTRX_NAME "H3"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH3
+#elif SOFTRX == H4
+#define SOFTRX_NAME "H4"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH4
+#elif SOFTRX == H5
+#define SOFTRX_NAME "H5"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH5
+#elif SOFTRX == H6
+#define SOFTRX_NAME "H6"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH6
+#elif SOFTRX == H7
+#define SOFTRX_NAME "H7"
+#define UART_PIN       PINH
+#define UART_RX_BIT    PINH7
+
+#elif SOFTRX == J0
+#define SOFTRX_NAME "J0"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ0
+#elif SOFTRX == J1
+#define SOFTRX_NAME "J1"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ1
+#elif SOFTRX == J2
+#define SOFTRX_NAME "J2"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ2
+#elif SOFTRX == J3
+#define SOFTRX_NAME "J3"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ3
+#elif SOFTRX == J4
+#define SOFTRX_NAME "J4"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ4
+#elif SOFTRX == J5
+#define SOFTRX_NAME "J5"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ5
+#elif SOFTRX == J6
+#define SOFTRX_NAME "J6"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ6
+#elif SOFTRX == J7
+#define SOFTRX_NAME "J7"
+#define UART_PIN       PINJ
+#define UART_RX_BIT    PINJ7
+
+#elif SOFTRX == K0
+#define SOFTRX_NAME "K0"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK0
+#elif SOFTRX == K1
+#define SOFTRX_NAME "K1"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK1
+#elif SOFTRX == K2
+#define SOFTRX_NAME "K2"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK2
+#elif SOFTRX == K3
+#define SOFTRX_NAME "K3"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK3
+#elif SOFTRX == K4
+#define SOFTRX_NAME "K4"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK4
+#elif SOFTRX == K5
+#define SOFTRX_NAME "K5"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK5
+#elif SOFTRX == K6
+#define SOFTRX_NAME "K6"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK6
+#elif SOFTRX == K7
+#define SOFTRX_NAME "K7"
+#define UART_PIN       PINK
+#define UART_RX_BIT    PINK7
+
+#elif SOFTRX == L0
+#define SOFTRX_NAME "L0"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL0
+#elif SOFTRX == L1
+#define SOFTRX_NAME "L1"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL1
+#elif SOFTRX == L2
+#define SOFTRX_NAME "L2"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL2
+#elif SOFTRX == L3
+#define SOFTRX_NAME "L3"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL3
+#elif SOFTRX == L4
+#define SOFTRX_NAME "L4"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL4
+#elif SOFTRX == L5
+#define SOFTRX_NAME "L5"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL5
+#elif SOFTRX == L6
+#define SOFTRX_NAME "L6"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL6
+#elif SOFTRX == L7
+#define SOFTRX_NAME "L7"
+#define UART_PIN       PINL
+#define UART_RX_BIT    PINL7
+
+#elif SOFTRX == A0
+#define SOFTRX_NAME "A0"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA0
+#elif SOFTRX == A1
+#define SOFTRX_NAME "A1"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA1
+#elif SOFTRX == A2
+#define SOFTRX_NAME "A2"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA2
+#elif SOFTRX == A3
+#define SOFTRX_NAME "A3"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA3
+#elif SOFTRX == A4
+#define SOFTRX_NAME "A4"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA4
+#elif SOFTRX == A5
+#define SOFTRX_NAME "A5"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA5
+#elif SOFTRX == A6
+#define SOFTRX_NAME "A6"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA6
+#elif SOFTRX == A7
+#define SOFTRX_NAME "A7"
+#define UART_PIN       PINA
+#define UART_RX_BIT    PINA7
+#else
+#error -------------------------------------------
+#error Unrecognized SOFTRX name.  Should be like "B5"
+#error -------------------------------------------
+#endif
+

+ 49 - 0
optiboot/stk500.h

@@ -0,0 +1,49 @@
+/* STK500 constants list, from AVRDUDE
+ *
+ * Trivial set of constants derived from Atmel App Note AVR061
+ * Not copyrighted.  Released to the public domain.
+ */
+
+#define STK_OK              0x10
+#define STK_FAILED          0x11  // Not used
+#define STK_UNKNOWN         0x12  // Not used
+#define STK_NODEVICE        0x13  // Not used
+#define STK_INSYNC          0x14  // ' '
+#define STK_NOSYNC          0x15  // Not used
+#define ADC_CHANNEL_ERROR   0x16  // Not used
+#define ADC_MEASURE_OK      0x17  // Not used
+#define PWM_CHANNEL_ERROR   0x18  // Not used
+#define PWM_ADJUST_OK       0x19  // Not used
+#define CRC_EOP             0x20  // 'SPACE'
+#define STK_GET_SYNC        0x30  // '0'
+#define STK_GET_SIGN_ON     0x31  // '1'
+#define STK_SET_PARAMETER   0x40  // '@'
+#define STK_GET_PARAMETER   0x41  // 'A'
+#define STK_SET_DEVICE      0x42  // 'B'
+#define STK_SET_DEVICE_EXT  0x45  // 'E'
+#define STK_ENTER_PROGMODE  0x50  // 'P'
+#define STK_LEAVE_PROGMODE  0x51  // 'Q'
+#define STK_CHIP_ERASE      0x52  // 'R'
+#define STK_CHECK_AUTOINC   0x53  // 'S'
+#define STK_LOAD_ADDRESS    0x55  // 'U'
+#define STK_UNIVERSAL       0x56  // 'V'
+#define STK_PROG_FLASH      0x60  // '`'
+#define STK_PROG_DATA       0x61  // 'a'
+#define STK_PROG_FUSE       0x62  // 'b'
+#define STK_PROG_LOCK       0x63  // 'c'
+#define STK_PROG_PAGE       0x64  // 'd'
+#define STK_PROG_FUSE_EXT   0x65  // 'e'
+#define STK_READ_FLASH      0x70  // 'p'
+#define STK_READ_DATA       0x71  // 'q'
+#define STK_READ_FUSE       0x72  // 'r'
+#define STK_READ_LOCK       0x73  // 's'
+#define STK_READ_PAGE       0x74  // 't'
+#define STK_READ_SIGN       0x75  // 'u'
+#define STK_READ_OSCCAL     0x76  // 'v'
+#define STK_READ_FUSE_EXT   0x77  // 'w'
+#define STK_READ_OSCCAL_EXT 0x78  // 'x'
+#define STK_SW_MAJOR        0x81  // ' '
+#define STK_SW_MINOR        0x82  // ' '
+
+/* AVR raw commands sent via STK_UNIVERSAL */
+#define AVR_OP_LOAD_EXT_ADDR  0x4d