Add bootloader files for ATmega1284/Sanguino
Added the optiboot bootloader, uses only 512kB of FLASH Includes .hex file is for 20MHz µC Clock and serial speed of 57k6
This commit is contained in:
parent
5bfba7720e
commit
f991bf23b2
6 changed files with 2195 additions and 0 deletions
|
@ -0,0 +1,470 @@
|
||||||
|
# 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...
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
# enter the parameters for the avrdude isp tool
|
||||||
|
ISPTOOL = stk500v2
|
||||||
|
ISPPORT = usb
|
||||||
|
ISPSPEED = -b 115200
|
||||||
|
|
||||||
|
MCU_TARGET = atmega168
|
||||||
|
LDSECTIONS = -Wl,--section-start=.text=0x3e00 -Wl,--section-start=.version=0x3ffe
|
||||||
|
|
||||||
|
# Build environments
|
||||||
|
# Start of some ugly makefile-isms to allow optiboot to be built
|
||||||
|
# in several different environments. See the README.TXT file for
|
||||||
|
# details.
|
||||||
|
|
||||||
|
# default
|
||||||
|
fixpath = $(1)
|
||||||
|
|
||||||
|
ifeq ($(ENV), arduino)
|
||||||
|
# For Arduino, we assume that we're connected to the optiboot directory
|
||||||
|
# included with the arduino distribution, which means that the full set
|
||||||
|
# of avr-tools are "right up there" in standard places.
|
||||||
|
TOOLROOT = ../../../tools
|
||||||
|
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||||
|
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||||
|
|
||||||
|
ifeq ($(OS), windows)
|
||||||
|
# On windows, SOME of the tool paths will need to have backslashes instead
|
||||||
|
# of forward slashes (because they use windows cmd.exe for execution instead
|
||||||
|
# of a unix/mingw shell?) We also have to ensure that a consistent shell
|
||||||
|
# is used even if a unix shell is installed (ie as part of WINAVR)
|
||||||
|
fixpath = $(subst /,\,$1)
|
||||||
|
SHELL = cmd.exe
|
||||||
|
endif
|
||||||
|
|
||||||
|
else ifeq ($(ENV), arduinodev)
|
||||||
|
# Arduino IDE source code environment. Use the unpacked compilers created
|
||||||
|
# by the build (you'll need to do "ant build" first.)
|
||||||
|
ifeq ($(OS), macosx)
|
||||||
|
TOOLROOT = ../../../../build/macosx/work/Arduino.app/Contents/Resources/Java/hardware/tools
|
||||||
|
endif
|
||||||
|
ifeq ($(OS), windows)
|
||||||
|
TOOLROOT = ../../../../build/windows/work/hardware/tools
|
||||||
|
endif
|
||||||
|
|
||||||
|
GCCROOT = $(TOOLROOT)/avr/bin/
|
||||||
|
AVRDUDE_CONF = -C$(TOOLROOT)/avr/etc/avrdude.conf
|
||||||
|
|
||||||
|
else
|
||||||
|
GCCROOT =
|
||||||
|
AVRDUDE_CONF =
|
||||||
|
endif
|
||||||
|
#
|
||||||
|
# End of build environment code.
|
||||||
|
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
ISPFUSES = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||||
|
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||||
|
-e -u -U lock:w:0x3f:m -U efuse:w:0x$(EFUSE):m \
|
||||||
|
-U hfuse:w:0x$(HFUSE):m -U lfuse:w:0x$(LFUSE):m
|
||||||
|
ISPFLASH = $(GCCROOT)avrdude $(AVRDUDE_CONF) -c $(ISPTOOL) \
|
||||||
|
-p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
|
||||||
|
-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x2f:m
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
OBJ = $(PROGRAM).o
|
||||||
|
OPTIMIZE = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls
|
||||||
|
|
||||||
|
DEFS =
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
CC = $(GCCROOT)avr-gcc
|
||||||
|
|
||||||
|
# Override is only needed by avr-lib build system.
|
||||||
|
|
||||||
|
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
|
||||||
|
override LDFLAGS = $(LDSECTIONS) -Wl,--relax -Wl,--gc-sections -nostartfiles -nostdlib
|
||||||
|
|
||||||
|
OBJCOPY = $(GCCROOT)avr-objcopy
|
||||||
|
OBJDUMP = $(call fixpath,$(GCCROOT)avr-objdump)
|
||||||
|
|
||||||
|
SIZE = $(GCCROOT)avr-size
|
||||||
|
|
||||||
|
# Test platforms
|
||||||
|
# Virtual boot block test
|
||||||
|
virboot328: TARGET = atmega328
|
||||||
|
virboot328: MCU_TARGET = atmega328p
|
||||||
|
virboot328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' '-DVIRTUAL_BOOT'
|
||||||
|
virboot328: AVR_FREQ = 16000000L
|
||||||
|
virboot328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||||
|
virboot328: $(PROGRAM)_atmega328.hex
|
||||||
|
virboot328: $(PROGRAM)_atmega328.lst
|
||||||
|
|
||||||
|
# 20MHz clocked platforms
|
||||||
|
#
|
||||||
|
# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue)
|
||||||
|
#
|
||||||
|
|
||||||
|
pro20: TARGET = pro_20mhz
|
||||||
|
pro20: MCU_TARGET = atmega168
|
||||||
|
pro20: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
pro20: AVR_FREQ = 20000000L
|
||||||
|
pro20: $(PROGRAM)_pro_20mhz.hex
|
||||||
|
pro20: $(PROGRAM)_pro_20mhz.lst
|
||||||
|
|
||||||
|
pro20_isp: pro20
|
||||||
|
pro20_isp: TARGET = pro_20mhz
|
||||||
|
# 2.7V brownout
|
||||||
|
pro20_isp: HFUSE = DD
|
||||||
|
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||||
|
pro20_isp: LFUSE = C6
|
||||||
|
# 512 byte boot
|
||||||
|
pro20_isp: EFUSE = 04
|
||||||
|
pro20_isp: isp
|
||||||
|
|
||||||
|
# 16MHz clocked platforms
|
||||||
|
#
|
||||||
|
# These are capable of 230400 baud, or 115200 baud on PC (Arduino Avrdude issue)
|
||||||
|
#
|
||||||
|
|
||||||
|
pro16: TARGET = pro_16MHz
|
||||||
|
pro16: MCU_TARGET = atmega168
|
||||||
|
pro16: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
pro16: AVR_FREQ = 16000000L
|
||||||
|
pro16: $(PROGRAM)_pro_16MHz.hex
|
||||||
|
pro16: $(PROGRAM)_pro_16MHz.lst
|
||||||
|
|
||||||
|
pro16_isp: pro16
|
||||||
|
pro16_isp: TARGET = pro_16MHz
|
||||||
|
# 2.7V brownout
|
||||||
|
pro16_isp: HFUSE = DD
|
||||||
|
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||||
|
pro16_isp: LFUSE = C6
|
||||||
|
# 512 byte boot
|
||||||
|
pro16_isp: EFUSE = 04
|
||||||
|
pro16_isp: isp
|
||||||
|
|
||||||
|
# Diecimila, Duemilanove with m168, and NG use identical bootloaders
|
||||||
|
# Call it "atmega168" for generality and clarity, keep "diecimila" for
|
||||||
|
# backward compatibility of makefile
|
||||||
|
#
|
||||||
|
atmega168: TARGET = atmega168
|
||||||
|
atmega168: MCU_TARGET = atmega168
|
||||||
|
atmega168: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
atmega168: AVR_FREQ = 16000000L
|
||||||
|
atmega168: $(PROGRAM)_atmega168.hex
|
||||||
|
atmega168: $(PROGRAM)_atmega168.lst
|
||||||
|
|
||||||
|
atmega168_isp: atmega168
|
||||||
|
atmega168_isp: TARGET = atmega168
|
||||||
|
# 2.7V brownout
|
||||||
|
atmega168_isp: HFUSE = DD
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atmega168_isp: LFUSE = FF
|
||||||
|
# 512 byte boot
|
||||||
|
atmega168_isp: EFUSE = 04
|
||||||
|
atmega168_isp: isp
|
||||||
|
|
||||||
|
diecimila: TARGET = diecimila
|
||||||
|
diecimila: MCU_TARGET = atmega168
|
||||||
|
diecimila: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
diecimila: AVR_FREQ = 16000000L
|
||||||
|
diecimila: $(PROGRAM)_diecimila.hex
|
||||||
|
diecimila: $(PROGRAM)_diecimila.lst
|
||||||
|
|
||||||
|
diecimila_isp: diecimila
|
||||||
|
diecimila_isp: TARGET = diecimila
|
||||||
|
# 2.7V brownout
|
||||||
|
diecimila_isp: HFUSE = DD
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
diecimila_isp: LFUSE = FF
|
||||||
|
# 512 byte boot
|
||||||
|
diecimila_isp: EFUSE = 04
|
||||||
|
diecimila_isp: isp
|
||||||
|
|
||||||
|
atmega328: TARGET = atmega328
|
||||||
|
atmega328: MCU_TARGET = atmega328p
|
||||||
|
atmega328: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
atmega328: AVR_FREQ = 16000000L
|
||||||
|
atmega328: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||||
|
atmega328: $(PROGRAM)_atmega328.hex
|
||||||
|
atmega328: $(PROGRAM)_atmega328.lst
|
||||||
|
|
||||||
|
atmega328_isp: atmega328
|
||||||
|
atmega328_isp: TARGET = atmega328
|
||||||
|
atmega328_isp: MCU_TARGET = atmega328p
|
||||||
|
# 512 byte boot, SPIEN
|
||||||
|
atmega328_isp: HFUSE = DE
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atmega328_isp: LFUSE = FF
|
||||||
|
# 2.7V brownout
|
||||||
|
atmega328_isp: EFUSE = 05
|
||||||
|
atmega328_isp: isp
|
||||||
|
|
||||||
|
atmega1284: TARGET = atmega1284p
|
||||||
|
atmega1284: MCU_TARGET = atmega1284p
|
||||||
|
atmega1284: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' '-DBIGBOOT'
|
||||||
|
atmega1284: AVR_FREQ = 16000000L
|
||||||
|
atmega1284: LDSECTIONS = -Wl,--section-start=.text=0x1fc00
|
||||||
|
atmega1284: $(PROGRAM)_atmega1284p.hex
|
||||||
|
atmega1284: $(PROGRAM)_atmega1284p.lst
|
||||||
|
|
||||||
|
atmega1284_isp: atmega1284
|
||||||
|
atmega1284_isp: TARGET = atmega1284p
|
||||||
|
atmega1284_isp: MCU_TARGET = atmega1284p
|
||||||
|
# 1024 byte boot
|
||||||
|
atmega1284_isp: HFUSE = DE
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atmega1284_isp: LFUSE = FF
|
||||||
|
# 2.7V brownout
|
||||||
|
atmega1284_isp: EFUSE = FD
|
||||||
|
atmega1284_isp: isp
|
||||||
|
|
||||||
|
# Sanguino has a minimum boot size of 1024 bytes, so enable extra functions
|
||||||
|
#
|
||||||
|
sanguino: TARGET = atmega644p
|
||||||
|
sanguino: MCU_TARGET = atmega644p
|
||||||
|
sanguino: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' '-DBIGBOOT'
|
||||||
|
sanguino: AVR_FREQ = 16000000L
|
||||||
|
sanguino: LDSECTIONS = -Wl,--section-start=.text=0xfc00
|
||||||
|
sanguino: $(PROGRAM)_atmega644p.hex
|
||||||
|
sanguino: $(PROGRAM)_atmega644p.lst
|
||||||
|
|
||||||
|
sanguino_isp: sanguino
|
||||||
|
sanguino_isp: TARGET = atmega644p
|
||||||
|
sanguino_isp: MCU_TARGET = atmega644p
|
||||||
|
# 1024 byte boot
|
||||||
|
sanguino_isp: HFUSE = DE
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
sanguino_isp: LFUSE = FF
|
||||||
|
# 2.7V brownout
|
||||||
|
sanguino_isp: EFUSE = 05
|
||||||
|
sanguino_isp: isp
|
||||||
|
|
||||||
|
# Mega has a minimum boot size of 1024 bytes, so enable extra functions
|
||||||
|
#mega: TARGET = atmega1280
|
||||||
|
mega: MCU_TARGET = atmega1280
|
||||||
|
mega: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200' '-DBIGBOOT'
|
||||||
|
mega: AVR_FREQ = 16000000L
|
||||||
|
mega: LDSECTIONS = -Wl,--section-start=.text=0x1fc00
|
||||||
|
mega: $(PROGRAM)_atmega1280.hex
|
||||||
|
mega: $(PROGRAM)_atmega1280.lst
|
||||||
|
|
||||||
|
mega_isp: mega
|
||||||
|
mega_isp: TARGET = atmega1280
|
||||||
|
mega_isp: MCU_TARGET = atmega1280
|
||||||
|
# 1024 byte boot
|
||||||
|
mega_isp: HFUSE = DE
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
mega_isp: LFUSE = FF
|
||||||
|
# 2.7V brownout
|
||||||
|
mega_isp: EFUSE = 05
|
||||||
|
mega_isp: isp
|
||||||
|
|
||||||
|
# ATmega8
|
||||||
|
#
|
||||||
|
atmega8: TARGET = atmega8
|
||||||
|
atmega8: MCU_TARGET = atmega8
|
||||||
|
atmega8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
atmega8: AVR_FREQ = 16000000L
|
||||||
|
atmega8: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||||
|
atmega8: $(PROGRAM)_atmega8.hex
|
||||||
|
atmega8: $(PROGRAM)_atmega8.lst
|
||||||
|
|
||||||
|
atmega8_isp: atmega8
|
||||||
|
atmega8_isp: TARGET = atmega8
|
||||||
|
atmega8_isp: MCU_TARGET = atmega8
|
||||||
|
# SPIEN, CKOPT, Bootsize=512B
|
||||||
|
atmega8_isp: HFUSE = CC
|
||||||
|
# 2.7V brownout, Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atmega8_isp: LFUSE = BF
|
||||||
|
atmega8_isp: isp
|
||||||
|
|
||||||
|
# ATmega88
|
||||||
|
#
|
||||||
|
atmega88: TARGET = atmega88
|
||||||
|
atmega88: MCU_TARGET = atmega88
|
||||||
|
atmega88: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
atmega88: AVR_FREQ = 16000000L
|
||||||
|
atmega88: LDSECTIONS = -Wl,--section-start=.text=0x1e00 -Wl,--section-start=.version=0x1ffe
|
||||||
|
atmega88: $(PROGRAM)_atmega88.hex
|
||||||
|
atmega88: $(PROGRAM)_atmega88.lst
|
||||||
|
|
||||||
|
atmega88_isp: atmega88
|
||||||
|
atmega88_isp: TARGET = atmega88
|
||||||
|
atmega88_isp: MCU_TARGET = atmega88
|
||||||
|
# 2.7V brownout
|
||||||
|
atmega88_isp: HFUSE = DD
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atemga88_isp: LFUSE = FF
|
||||||
|
# 512 byte boot
|
||||||
|
atmega88_isp: EFUSE = 04
|
||||||
|
atmega88_isp: isp
|
||||||
|
|
||||||
|
|
||||||
|
# 8MHz clocked platforms
|
||||||
|
#
|
||||||
|
# These are capable of 115200 baud
|
||||||
|
#
|
||||||
|
|
||||||
|
lilypad: TARGET = lilypad
|
||||||
|
lilypad: MCU_TARGET = atmega168
|
||||||
|
lilypad: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
lilypad: AVR_FREQ = 8000000L
|
||||||
|
lilypad: $(PROGRAM)_lilypad.hex
|
||||||
|
lilypad: $(PROGRAM)_lilypad.lst
|
||||||
|
|
||||||
|
lilypad_isp: lilypad
|
||||||
|
lilypad_isp: TARGET = lilypad
|
||||||
|
# 2.7V brownout
|
||||||
|
lilypad_isp: HFUSE = DD
|
||||||
|
# Internal 8MHz osc (8MHz) Slow rising power
|
||||||
|
lilypad_isp: LFUSE = E2
|
||||||
|
# 512 byte boot
|
||||||
|
lilypad_isp: EFUSE = 04
|
||||||
|
lilypad_isp: isp
|
||||||
|
|
||||||
|
lilypad_resonator: TARGET = lilypad_resonator
|
||||||
|
lilypad_resonator: MCU_TARGET = atmega168
|
||||||
|
lilypad_resonator: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
lilypad_resonator: AVR_FREQ = 8000000L
|
||||||
|
lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
|
||||||
|
lilypad_resonator: $(PROGRAM)_lilypad_resonator.lst
|
||||||
|
|
||||||
|
lilypad_resonator_isp: lilypad_resonator
|
||||||
|
lilypad_resonator_isp: TARGET = lilypad_resonator
|
||||||
|
# 2.7V brownout
|
||||||
|
lilypad_resonator_isp: HFUSE = DD
|
||||||
|
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||||
|
lilypad_resonator_isp: LFUSE = C6
|
||||||
|
# 512 byte boot
|
||||||
|
lilypad_resonator_isp: EFUSE = 04
|
||||||
|
lilypad_resonator_isp: isp
|
||||||
|
|
||||||
|
pro8: TARGET = pro_8MHz
|
||||||
|
pro8: MCU_TARGET = atmega168
|
||||||
|
pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
pro8: AVR_FREQ = 8000000L
|
||||||
|
pro8: $(PROGRAM)_pro_8MHz.hex
|
||||||
|
pro8: $(PROGRAM)_pro_8MHz.lst
|
||||||
|
|
||||||
|
pro8_isp: pro8
|
||||||
|
pro8_isp: TARGET = pro_8MHz
|
||||||
|
# 2.7V brownout
|
||||||
|
pro8_isp: HFUSE = DD
|
||||||
|
# Full swing xtal (20MHz) 258CK/14CK+4.1ms
|
||||||
|
pro8_isp: LFUSE = C6
|
||||||
|
# 512 byte boot
|
||||||
|
pro8_isp: EFUSE = 04
|
||||||
|
pro8_isp: isp
|
||||||
|
|
||||||
|
atmega328_pro8: TARGET = atmega328_pro_8MHz
|
||||||
|
atmega328_pro8: MCU_TARGET = atmega328p
|
||||||
|
atmega328_pro8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
|
||||||
|
atmega328_pro8: AVR_FREQ = 8000000L
|
||||||
|
atmega328_pro8: LDSECTIONS = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
|
||||||
|
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
|
||||||
|
atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.lst
|
||||||
|
|
||||||
|
atmega328_pro8_isp: atmega328_pro8
|
||||||
|
atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
|
||||||
|
atmega328_pro8_isp: MCU_TARGET = atmega328p
|
||||||
|
# 512 byte boot, SPIEN
|
||||||
|
atmega328_pro8_isp: HFUSE = DE
|
||||||
|
# Low power xtal (16MHz) 16KCK/14CK+65ms
|
||||||
|
atmega328_pro8_isp: LFUSE = FF
|
||||||
|
# 2.7V brownout
|
||||||
|
atmega328_pro8_isp: EFUSE = 05
|
||||||
|
atmega328_pro8_isp: isp
|
||||||
|
|
||||||
|
# 1MHz clocked platforms
|
||||||
|
#
|
||||||
|
# These are capable of 9600 baud
|
||||||
|
#
|
||||||
|
|
||||||
|
luminet: TARGET = luminet
|
||||||
|
luminet: MCU_TARGET = attiny84
|
||||||
|
luminet: CFLAGS += '-DLED_START_FLASHES=3' '-DSOFT_UART' '-DBAUD_RATE=9600'
|
||||||
|
luminet: CFLAGS += '-DVIRTUAL_BOOT_PARTITION'
|
||||||
|
luminet: AVR_FREQ = 1000000L
|
||||||
|
luminet: LDSECTIONS = -Wl,--section-start=.text=0x1d00 -Wl,--section-start=.version=0x1efe
|
||||||
|
luminet: $(PROGRAM)_luminet.hex
|
||||||
|
luminet: $(PROGRAM)_luminet.lst
|
||||||
|
|
||||||
|
luminet_isp: luminet
|
||||||
|
luminet_isp: TARGET = luminet
|
||||||
|
luminet_isp: MCU_TARGET = attiny84
|
||||||
|
# Brownout disabled
|
||||||
|
luminet_isp: HFUSE = DF
|
||||||
|
# 1MHz internal oscillator, slowly rising power
|
||||||
|
luminet_isp: LFUSE = 62
|
||||||
|
# Self-programming enable
|
||||||
|
luminet_isp: EFUSE = FE
|
||||||
|
luminet_isp: isp
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generic build instructions
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
isp: $(TARGET)
|
||||||
|
$(ISPFUSES)
|
||||||
|
$(ISPFLASH)
|
||||||
|
|
||||||
|
isp-stk500: $(PROGRAM)_$(TARGET).hex
|
||||||
|
$(STK500-1)
|
||||||
|
$(STK500-2)
|
||||||
|
|
||||||
|
%.elf: $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||||
|
$(SIZE) $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
|
||||||
|
|
||||||
|
%.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 $< $@
|
|
@ -0,0 +1,848 @@
|
||||||
|
/* Modified to use out for SPM access
|
||||||
|
** Peter Knight, Optiboot project http://optiboot.googlecode.com
|
||||||
|
**
|
||||||
|
** Todo: Tidy up
|
||||||
|
**
|
||||||
|
** "_short" routines execute 1 cycle faster and use 1 less word of flash
|
||||||
|
** by using "out" instruction instead of "sts".
|
||||||
|
**
|
||||||
|
** Additional elpm variants that trust the value of RAMPZ
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE. */
|
||||||
|
|
||||||
|
/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */
|
||||||
|
|
||||||
|
#ifndef _AVR_BOOT_H_
|
||||||
|
#define _AVR_BOOT_H_ 1
|
||||||
|
|
||||||
|
/** \file */
|
||||||
|
/** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities
|
||||||
|
\code
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/boot.h>
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
The macros in this module provide a C language interface to the
|
||||||
|
bootloader support functionality of certain AVR processors. These
|
||||||
|
macros are designed to work with all sizes of flash memory.
|
||||||
|
|
||||||
|
Global interrupts are not automatically disabled for these macros. It
|
||||||
|
is left up to the programmer to do this. See the code example below.
|
||||||
|
Also see the processor datasheet for caveats on having global interrupts
|
||||||
|
enabled during writing of the Flash.
|
||||||
|
|
||||||
|
\note Not all AVR processors provide bootloader support. See your
|
||||||
|
processor datasheet to see if it provides bootloader support.
|
||||||
|
|
||||||
|
\todo From email with Marek: On smaller devices (all except ATmega64/128),
|
||||||
|
__SPM_REG is in the I/O space, accessible with the shorter "in" and "out"
|
||||||
|
instructions - since the boot loader has a limited size, this could be an
|
||||||
|
important optimization.
|
||||||
|
|
||||||
|
\par API Usage Example
|
||||||
|
The following code shows typical usage of the boot API.
|
||||||
|
|
||||||
|
\code
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
void boot_program_page (uint32_t page, uint8_t *buf)
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
uint8_t sreg;
|
||||||
|
|
||||||
|
// Disable interrupts.
|
||||||
|
|
||||||
|
sreg = SREG;
|
||||||
|
cli();
|
||||||
|
|
||||||
|
eeprom_busy_wait ();
|
||||||
|
|
||||||
|
boot_page_erase (page);
|
||||||
|
boot_spm_busy_wait (); // Wait until the memory is erased.
|
||||||
|
|
||||||
|
for (i=0; i<SPM_PAGESIZE; i+=2)
|
||||||
|
{
|
||||||
|
// Set up little-endian word.
|
||||||
|
|
||||||
|
uint16_t w = *buf++;
|
||||||
|
w += (*buf++) << 8;
|
||||||
|
|
||||||
|
boot_page_fill (page + i, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
boot_page_write (page); // Store buffer in flash page.
|
||||||
|
boot_spm_busy_wait(); // Wait until the memory is written.
|
||||||
|
|
||||||
|
// Reenable RWW-section again. We need this if we want to jump back
|
||||||
|
// to the application after bootloading.
|
||||||
|
|
||||||
|
boot_rww_enable ();
|
||||||
|
|
||||||
|
// Re-enable interrupts (if they were ever enabled).
|
||||||
|
|
||||||
|
SREG = sreg;
|
||||||
|
}\endcode */
|
||||||
|
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* Check for SPM Control Register in processor. */
|
||||||
|
#if defined (SPMCSR)
|
||||||
|
# define __SPM_REG SPMCSR
|
||||||
|
#elif defined (SPMCR)
|
||||||
|
# define __SPM_REG SPMCR
|
||||||
|
#else
|
||||||
|
# error AVR processor does not provide bootloader support!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Check for SPM Enable bit. */
|
||||||
|
#if defined(SPMEN)
|
||||||
|
# define __SPM_ENABLE SPMEN
|
||||||
|
#elif defined(SELFPRGEN)
|
||||||
|
# define __SPM_ENABLE SELFPRGEN
|
||||||
|
#else
|
||||||
|
# error Cannot find SPM Enable bit definition!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def BOOTLOADER_SECTION
|
||||||
|
|
||||||
|
Used to declare a function or variable to be placed into a
|
||||||
|
new section called .bootloader. This section and its contents
|
||||||
|
can then be relocated to any address (such as the bootloader
|
||||||
|
NRWW area) at link-time. */
|
||||||
|
|
||||||
|
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
|
||||||
|
|
||||||
|
/* Create common bit definitions. */
|
||||||
|
#ifdef ASB
|
||||||
|
#define __COMMON_ASB ASB
|
||||||
|
#else
|
||||||
|
#define __COMMON_ASB RWWSB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ASRE
|
||||||
|
#define __COMMON_ASRE ASRE
|
||||||
|
#else
|
||||||
|
#define __COMMON_ASRE RWWSRE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define the bit positions of the Boot Lock Bits. */
|
||||||
|
|
||||||
|
#define BLB12 5
|
||||||
|
#define BLB11 4
|
||||||
|
#define BLB02 3
|
||||||
|
#define BLB01 2
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_spm_interrupt_enable()
|
||||||
|
Enable the SPM interrupt. */
|
||||||
|
|
||||||
|
#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_spm_interrupt_disable()
|
||||||
|
Disable the SPM interrupt. */
|
||||||
|
|
||||||
|
#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_is_spm_interrupt()
|
||||||
|
Check if the SPM interrupt is enabled. */
|
||||||
|
|
||||||
|
#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_rww_busy()
|
||||||
|
Check if the RWW section is busy. */
|
||||||
|
|
||||||
|
#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_spm_busy()
|
||||||
|
Check if the SPM instruction is busy. */
|
||||||
|
|
||||||
|
#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_spm_busy_wait()
|
||||||
|
Wait while the SPM instruction is busy. */
|
||||||
|
|
||||||
|
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
|
||||||
|
|
||||||
|
#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
|
||||||
|
#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
|
||||||
|
#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
|
||||||
|
#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
|
||||||
|
#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
|
||||||
|
|
||||||
|
#define __boot_page_fill_short(address, data) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r0, %3\n\t" \
|
||||||
|
"out %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
"clr r1\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||||
|
"z" ((uint16_t)address), \
|
||||||
|
"r" ((uint16_t)data) \
|
||||||
|
: "r0" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_fill_normal(address, data) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r0, %3\n\t" \
|
||||||
|
"sts %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_fill_alternate(address, data)\
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r0, %3\n\t" \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
".word 0xffff\n\t" \
|
||||||
|
"nop\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_fill_extended(address, data) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r0, %4\n\t" \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"sts %1, %C3\n\t" \
|
||||||
|
"sts %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
"clr r1\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||||
|
"r" ((uint32_t)address), \
|
||||||
|
"r" ((uint16_t)data) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_fill_extended_short(address, data) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r0, %4\n\t" \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"out %1, %C3\n\t" \
|
||||||
|
"out %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
"clr r1\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_FILL), \
|
||||||
|
"r" ((uint32_t)address), \
|
||||||
|
"r" ((uint16_t)data) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_erase_short(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"out %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||||
|
"z" ((uint16_t)address) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
#define __boot_page_erase_normal(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %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_erase_alternate(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
".word 0xffff\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||||
|
"z" ((uint16_t)address) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_erase_extended(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"sts %1, %C3\n\t" \
|
||||||
|
"sts %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||||
|
"r" ((uint32_t)address) \
|
||||||
|
: "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
#define __boot_page_erase_extended_short(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"out %1, %C3\n\t" \
|
||||||
|
"out %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_ERASE), \
|
||||||
|
"r" ((uint32_t)address) \
|
||||||
|
: "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_write_short(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"out %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||||
|
"z" ((uint16_t)address) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_write_normal(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %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_page_write_alternate(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
".word 0xffff\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||||
|
"z" ((uint16_t)address) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_page_write_extended(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"sts %1, %C3\n\t" \
|
||||||
|
"sts %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_MEM_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||||
|
"r" ((uint32_t)address) \
|
||||||
|
: "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
#define __boot_page_write_extended_short(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"movw r30, %A3\n\t" \
|
||||||
|
"out %1, %C3\n\t" \
|
||||||
|
"out %0, %2\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"i" (_SFR_IO_ADDR(RAMPZ)), \
|
||||||
|
"r" ((uint8_t)__BOOT_PAGE_WRITE), \
|
||||||
|
"r" ((uint32_t)address) \
|
||||||
|
: "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_rww_enable_short() \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"out %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_rww_enable() \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_rww_enable_alternate() \
|
||||||
|
(__extension__({ \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
".word 0xffff\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_RWW_ENABLE) \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
/* From the mega16/mega128 data sheets (maybe others):
|
||||||
|
|
||||||
|
Bits by SPM To set the Boot Loader Lock bits, write the desired data to
|
||||||
|
R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
|
||||||
|
after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
|
||||||
|
that may prevent the Application and Boot Loader section from any
|
||||||
|
software update by the MCU.
|
||||||
|
|
||||||
|
If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
|
||||||
|
will be programmed if an SPM instruction is executed within four cycles
|
||||||
|
after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
|
||||||
|
don't care during this operation, but for future compatibility it is
|
||||||
|
recommended to load the Z-pointer with $0001 (same as used for reading the
|
||||||
|
Lock bits). For future compatibility It is also recommended to set bits 7,
|
||||||
|
6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
|
||||||
|
Lock bits the entire Flash can be read during the operation. */
|
||||||
|
|
||||||
|
#define __boot_lock_bits_set_short(lock_bits) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"ldi r30, 1\n\t" \
|
||||||
|
"ldi r31, 0\n\t" \
|
||||||
|
"mov r0, %2\n\t" \
|
||||||
|
"out %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||||
|
"r" (value) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_lock_bits_set(lock_bits) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"ldi r30, 1\n\t" \
|
||||||
|
"ldi r31, 0\n\t" \
|
||||||
|
"mov r0, %2\n\t" \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||||
|
"r" (value) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define __boot_lock_bits_set_alternate(lock_bits) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint8_t value = (uint8_t)(~(lock_bits)); \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"ldi r30, 1\n\t" \
|
||||||
|
"ldi r31, 0\n\t" \
|
||||||
|
"mov r0, %2\n\t" \
|
||||||
|
"sts %0, %1\n\t" \
|
||||||
|
"spm\n\t" \
|
||||||
|
".word 0xffff\n\t" \
|
||||||
|
"nop\n\t" \
|
||||||
|
: \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||||
|
"r" (value) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
}))
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reading lock and fuse bits:
|
||||||
|
|
||||||
|
Similarly to writing the lock bits above, set BLBSET and SPMEN (or
|
||||||
|
SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
|
||||||
|
LPM instruction.
|
||||||
|
|
||||||
|
Z address: contents:
|
||||||
|
0x0000 low fuse bits
|
||||||
|
0x0001 lock bits
|
||||||
|
0x0002 extended fuse bits
|
||||||
|
0x0003 high fuse bits
|
||||||
|
|
||||||
|
Sounds confusing, doesn't it?
|
||||||
|
|
||||||
|
Unlike the macros in pgmspace.h, no need to care for non-enhanced
|
||||||
|
cores here as these old cores do not provide SPM support anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def GET_LOW_FUSE_BITS
|
||||||
|
address to read the low fuse bits, using boot_lock_fuse_bits_get
|
||||||
|
*/
|
||||||
|
#define GET_LOW_FUSE_BITS (0x0000)
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def GET_LOCK_BITS
|
||||||
|
address to read the lock bits, using boot_lock_fuse_bits_get
|
||||||
|
*/
|
||||||
|
#define GET_LOCK_BITS (0x0001)
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def GET_EXTENDED_FUSE_BITS
|
||||||
|
address to read the extended fuse bits, using boot_lock_fuse_bits_get
|
||||||
|
*/
|
||||||
|
#define GET_EXTENDED_FUSE_BITS (0x0002)
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def GET_HIGH_FUSE_BITS
|
||||||
|
address to read the high fuse bits, using boot_lock_fuse_bits_get
|
||||||
|
*/
|
||||||
|
#define GET_HIGH_FUSE_BITS (0x0003)
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_lock_fuse_bits_get(address)
|
||||||
|
|
||||||
|
Read the lock or fuse bits at \c address.
|
||||||
|
|
||||||
|
Parameter \c address can be any of GET_LOW_FUSE_BITS,
|
||||||
|
GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS.
|
||||||
|
|
||||||
|
\note The lock and fuse bits returned are the physical values,
|
||||||
|
i.e. a bit returned as 0 means the corresponding fuse or lock bit
|
||||||
|
is programmed.
|
||||||
|
*/
|
||||||
|
#define boot_lock_fuse_bits_get_short(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint8_t __result; \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"ldi r30, %3\n\t" \
|
||||||
|
"ldi r31, 0\n\t" \
|
||||||
|
"out %1, %2\n\t" \
|
||||||
|
"lpm %0, Z\n\t" \
|
||||||
|
: "=r" (__result) \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||||
|
"M" (address) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
__result; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define boot_lock_fuse_bits_get(address) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint8_t __result; \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"ldi r30, %3\n\t" \
|
||||||
|
"ldi r31, 0\n\t" \
|
||||||
|
"sts %1, %2\n\t" \
|
||||||
|
"lpm %0, Z\n\t" \
|
||||||
|
: "=r" (__result) \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t)__BOOT_LOCK_BITS_SET), \
|
||||||
|
"M" (address) \
|
||||||
|
: "r0", "r30", "r31" \
|
||||||
|
); \
|
||||||
|
__result; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_signature_byte_get(address)
|
||||||
|
|
||||||
|
Read the Signature Row byte at \c address. For some MCU types,
|
||||||
|
this function can also retrieve the factory-stored oscillator
|
||||||
|
calibration bytes.
|
||||||
|
|
||||||
|
Parameter \c address can be 0-0x1f as documented by the datasheet.
|
||||||
|
\note The values are MCU type dependent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
|
||||||
|
|
||||||
|
#define boot_signature_byte_get_short(addr) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint16_t __addr16 = (uint16_t)(addr); \
|
||||||
|
uint8_t __result; \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"out %1, %2\n\t" \
|
||||||
|
"lpm %0, Z" "\n\t" \
|
||||||
|
: "=r" (__result) \
|
||||||
|
: "i" (_SFR_IO_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||||
|
"z" (__addr16) \
|
||||||
|
); \
|
||||||
|
__result; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
#define boot_signature_byte_get(addr) \
|
||||||
|
(__extension__({ \
|
||||||
|
uint16_t __addr16 = (uint16_t)(addr); \
|
||||||
|
uint8_t __result; \
|
||||||
|
__asm__ __volatile__ \
|
||||||
|
( \
|
||||||
|
"sts %1, %2\n\t" \
|
||||||
|
"lpm %0, Z" "\n\t" \
|
||||||
|
: "=r" (__result) \
|
||||||
|
: "i" (_SFR_MEM_ADDR(__SPM_REG)), \
|
||||||
|
"r" ((uint8_t) __BOOT_SIGROW_READ), \
|
||||||
|
"z" (__addr16) \
|
||||||
|
); \
|
||||||
|
__result; \
|
||||||
|
}))
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_page_fill(address, data)
|
||||||
|
|
||||||
|
Fill the bootloader temporary page buffer for flash
|
||||||
|
address with data word.
|
||||||
|
|
||||||
|
\note The address is a byte address. The data is a word. The AVR
|
||||||
|
writes data to the buffer a word at a time, but addresses the buffer
|
||||||
|
per byte! So, increment your address by 2 between calls, and send 2
|
||||||
|
data bytes in a word format! The LSB of the data is written to the lower
|
||||||
|
address; the MSB of the data is written to the higher address.*/
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_page_erase(address)
|
||||||
|
|
||||||
|
Erase the flash page that contains address.
|
||||||
|
|
||||||
|
\note address is a byte address in flash, not a word address. */
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_page_write(address)
|
||||||
|
|
||||||
|
Write the bootloader temporary page buffer
|
||||||
|
to flash page that contains address.
|
||||||
|
|
||||||
|
\note address is a byte address in flash, not a word address. */
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_rww_enable()
|
||||||
|
|
||||||
|
Enable the Read-While-Write memory section. */
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
\def boot_lock_bits_set(lock_bits)
|
||||||
|
|
||||||
|
Set the bootloader lock bits.
|
||||||
|
|
||||||
|
\param lock_bits A mask of which Boot Loader Lock Bits to set.
|
||||||
|
|
||||||
|
\note In this context, a 'set bit' will be written to a zero value.
|
||||||
|
Note also that only BLBxx bits can be programmed by this command.
|
||||||
|
|
||||||
|
For example, to disallow the SPM instruction from writing to the Boot
|
||||||
|
Loader memory section of flash, you would use this macro as such:
|
||||||
|
|
||||||
|
\code
|
||||||
|
boot_lock_bits_set (_BV (BLB11));
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\note Like any lock bits, the Boot Loader Lock Bits, once set,
|
||||||
|
cannot be cleared again except by a chip erase which will in turn
|
||||||
|
also erase the boot loader itself. */
|
||||||
|
|
||||||
|
/* Normal versions of the macros use 16-bit addresses.
|
||||||
|
Extended versions of the macros use 32-bit addresses.
|
||||||
|
Alternate versions of the macros use 16-bit addresses and require special
|
||||||
|
instruction sequences after LPM.
|
||||||
|
|
||||||
|
FLASHEND is defined in the ioXXXX.h file.
|
||||||
|
USHRT_MAX is defined in <limits.h>. */
|
||||||
|
|
||||||
|
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
|
||||||
|
|| defined(__AVR_ATmega323__)
|
||||||
|
|
||||||
|
/* Alternate: ATmega161/163/323 and 16 bit address */
|
||||||
|
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
|
||||||
|
#define boot_page_erase(address) __boot_page_erase_alternate(address)
|
||||||
|
#define boot_page_write(address) __boot_page_write_alternate(address)
|
||||||
|
#define boot_rww_enable() __boot_rww_enable_alternate()
|
||||||
|
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
|
||||||
|
|
||||||
|
#elif (FLASHEND > USHRT_MAX)
|
||||||
|
|
||||||
|
/* Extended: >16 bit address */
|
||||||
|
#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data)
|
||||||
|
#define boot_page_erase(address) __boot_page_erase_extended_short(address)
|
||||||
|
#define boot_page_write(address) __boot_page_write_extended_short(address)
|
||||||
|
#define boot_rww_enable() __boot_rww_enable_short()
|
||||||
|
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Normal: 16 bit address */
|
||||||
|
#define boot_page_fill(address, data) __boot_page_fill_short(address, data)
|
||||||
|
#define boot_page_erase(address) __boot_page_erase_short(address)
|
||||||
|
#define boot_page_write(address) __boot_page_write_short(address)
|
||||||
|
#define boot_rww_enable() __boot_rww_enable_short()
|
||||||
|
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
|
||||||
|
Same as boot_page_fill() except it waits for eeprom and spm operations to
|
||||||
|
complete before filling the page. */
|
||||||
|
|
||||||
|
#define boot_page_fill_safe(address, data) \
|
||||||
|
do { \
|
||||||
|
boot_spm_busy_wait(); \
|
||||||
|
eeprom_busy_wait(); \
|
||||||
|
boot_page_fill(address, data); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
|
||||||
|
Same as boot_page_erase() except it waits for eeprom and spm operations to
|
||||||
|
complete before erasing the page. */
|
||||||
|
|
||||||
|
#define boot_page_erase_safe(address) \
|
||||||
|
do { \
|
||||||
|
boot_spm_busy_wait(); \
|
||||||
|
eeprom_busy_wait(); \
|
||||||
|
boot_page_erase (address); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
|
||||||
|
Same as boot_page_write() except it waits for eeprom and spm operations to
|
||||||
|
complete before writing the page. */
|
||||||
|
|
||||||
|
#define boot_page_write_safe(address) \
|
||||||
|
do { \
|
||||||
|
boot_spm_busy_wait(); \
|
||||||
|
eeprom_busy_wait(); \
|
||||||
|
boot_page_write (address); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
|
||||||
|
Same as boot_rww_enable() except waits for eeprom and spm operations to
|
||||||
|
complete before enabling the RWW mameory. */
|
||||||
|
|
||||||
|
#define boot_rww_enable_safe() \
|
||||||
|
do { \
|
||||||
|
boot_spm_busy_wait(); \
|
||||||
|
eeprom_busy_wait(); \
|
||||||
|
boot_rww_enable(); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/** \ingroup avr_boot
|
||||||
|
|
||||||
|
Same as boot_lock_bits_set() except waits for eeprom and spm operations to
|
||||||
|
complete before setting the lock bits. */
|
||||||
|
|
||||||
|
#define boot_lock_bits_set_safe(lock_bits) \
|
||||||
|
do { \
|
||||||
|
boot_spm_busy_wait(); \
|
||||||
|
eeprom_busy_wait(); \
|
||||||
|
boot_lock_bits_set (lock_bits); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif /* _AVR_BOOT_H_ */
|
|
@ -0,0 +1,724 @@
|
||||||
|
/**********************************************************/
|
||||||
|
/* -Wl,-section-start=bootloader=0x1fc00 */
|
||||||
|
/* Optiboot bootloader for Arduino */
|
||||||
|
/* */
|
||||||
|
/* http://optiboot.googlecode.com */
|
||||||
|
/* */
|
||||||
|
/* Arduino-maintained version : See README.TXT */
|
||||||
|
/* http://code.google.com/p/arduino/ */
|
||||||
|
/* */
|
||||||
|
/* Heavily optimised bootloader that is faster and */
|
||||||
|
/* smaller than the Arduino standard bootloader */
|
||||||
|
/* */
|
||||||
|
/* Enhancements: */
|
||||||
|
/* Fits in 512 bytes, saving 1.5K of code space */
|
||||||
|
/* Background page erasing speeds up programming */
|
||||||
|
/* Higher baud rate speeds up programming */
|
||||||
|
/* Written almost entirely in C */
|
||||||
|
/* Customisable timeout with accurate timeconstant */
|
||||||
|
/* Optional virtual UART. No hardware UART required. */
|
||||||
|
/* Optional virtual boot partition for devices without. */
|
||||||
|
/* */
|
||||||
|
/* What you lose: */
|
||||||
|
/* Implements a skeleton STK500 protocol which is */
|
||||||
|
/* missing several features including EEPROM */
|
||||||
|
/* programming and non-page-aligned writes */
|
||||||
|
/* High baud rate breaks compatibility with standard */
|
||||||
|
/* Arduino flash settings */
|
||||||
|
/* */
|
||||||
|
/* Fully supported: */
|
||||||
|
/* ATmega168 based devices (Diecimila etc) */
|
||||||
|
/* ATmega328P based devices (Duemilanove etc) */
|
||||||
|
/* */
|
||||||
|
/* Alpha test */
|
||||||
|
/* ATmega1280 based devices (Arduino Mega) */
|
||||||
|
/* */
|
||||||
|
/* Work in progress: */
|
||||||
|
/* ATmega644P based devices (Sanguino) */
|
||||||
|
/* ATtiny84 based devices (Luminet) */
|
||||||
|
/* */
|
||||||
|
/* Does not support: */
|
||||||
|
/* USB based devices (eg. Teensy) */
|
||||||
|
/* */
|
||||||
|
/* Assumptions: */
|
||||||
|
/* The code makes several assumptions that reduce the */
|
||||||
|
/* code size. They are all true after a hardware reset, */
|
||||||
|
/* but may not be true if the bootloader is called by */
|
||||||
|
/* other means or on other hardware. */
|
||||||
|
/* No interrupts can occur */
|
||||||
|
/* UART and Timer 1 are set to their reset state */
|
||||||
|
/* SP points to RAMEND */
|
||||||
|
/* */
|
||||||
|
/* Code builds on code, libraries and optimisations from: */
|
||||||
|
/* stk500boot.c by Jason P. Kyle */
|
||||||
|
/* Arduino bootloader http://arduino.cc */
|
||||||
|
/* Spiff's 1K bootloader http://spiffie.org/know/arduino_1k_bootloader/bootloader.shtml */
|
||||||
|
/* avr-libc project http://nongnu.org/avr-libc */
|
||||||
|
/* Adaboot http://www.ladyada.net/library/arduino/bootloader.html */
|
||||||
|
/* AVR305 Atmel Application Note */
|
||||||
|
/* */
|
||||||
|
/* This program is free software; you can redistribute it */
|
||||||
|
/* and/or modify it under the terms of the GNU General */
|
||||||
|
/* Public License as published by the Free Software */
|
||||||
|
/* Foundation; either version 2 of the License, or */
|
||||||
|
/* (at your option) any later version. */
|
||||||
|
/* */
|
||||||
|
/* This program is distributed in the hope that it will */
|
||||||
|
/* be useful, but WITHOUT ANY WARRANTY; without even the */
|
||||||
|
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
|
||||||
|
/* PARTICULAR PURPOSE. See the GNU General Public */
|
||||||
|
/* License for more details. */
|
||||||
|
/* */
|
||||||
|
/* You should have received a copy of the GNU General */
|
||||||
|
/* Public License along with this program; if not, write */
|
||||||
|
/* to the Free Software Foundation, Inc., */
|
||||||
|
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
/* */
|
||||||
|
/* Licence can be viewed at */
|
||||||
|
/* http://www.fsf.org/licenses/gpl.txt */
|
||||||
|
/* */
|
||||||
|
/**********************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/* */
|
||||||
|
/* Optional defines: */
|
||||||
|
/* */
|
||||||
|
/**********************************************************/
|
||||||
|
/* */
|
||||||
|
/* BIG_BOOT: */
|
||||||
|
/* Build a 1k bootloader, not 512 bytes. This turns on */
|
||||||
|
/* extra functionality. */
|
||||||
|
/* */
|
||||||
|
/* BAUD_RATE: */
|
||||||
|
/* Set bootloader baud rate. */
|
||||||
|
/* */
|
||||||
|
/* LUDICROUS_SPEED: */
|
||||||
|
/* 230400 baud :-) */
|
||||||
|
/* */
|
||||||
|
/* SOFT_UART: */
|
||||||
|
/* Use AVR305 soft-UART instead of hardware UART. */
|
||||||
|
/* */
|
||||||
|
/* LED_START_FLASHES: */
|
||||||
|
/* Number of LED flashes on bootup. */
|
||||||
|
/* */
|
||||||
|
/* LED_DATA_FLASH: */
|
||||||
|
/* Flash LED when transferring data. For boards without */
|
||||||
|
/* TX or RX LEDs, or for people who like blinky lights. */
|
||||||
|
/* */
|
||||||
|
/* SUPPORT_EEPROM: */
|
||||||
|
/* Support reading and writing from EEPROM. This is not */
|
||||||
|
/* used by Arduino, so off by default. */
|
||||||
|
/* */
|
||||||
|
/* TIMEOUT_MS: */
|
||||||
|
/* Bootloader timeout period, in milliseconds. */
|
||||||
|
/* 500,1000,2000,4000,8000 supported. */
|
||||||
|
/* */
|
||||||
|
/**********************************************************/
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/* 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. */
|
||||||
|
/* */
|
||||||
|
/**********************************************************/
|
||||||
|
|
||||||
|
/**********************************************************/
|
||||||
|
/* Edit History: */
|
||||||
|
/* */
|
||||||
|
/* 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 4
|
||||||
|
#define OPTIBOOT_MINVER 5
|
||||||
|
|
||||||
|
#define MAKESTR(a) #a
|
||||||
|
#define MAKEVER(a, b) MAKESTR(a*256+b)
|
||||||
|
|
||||||
|
asm(" .section .version\n"
|
||||||
|
"optiboot_version: .word " MAKEVER(OPTIBOOT_MAJVER, OPTIBOOT_MINVER) "\n"
|
||||||
|
" .section .text\n");
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
|
||||||
|
// <avr/boot.h> uses sts instructions, but this version uses out instructions
|
||||||
|
// This saves cycles and program memory.
|
||||||
|
#include "boot.h"
|
||||||
|
|
||||||
|
|
||||||
|
// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
|
||||||
|
|
||||||
|
#include "pin_defs.h"
|
||||||
|
#include "stk500.h"
|
||||||
|
|
||||||
|
#ifndef LED_START_FLASHES
|
||||||
|
#define LED_START_FLASHES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LUDICROUS_SPEED
|
||||||
|
#define BAUD_RATE 230400L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* set the UART baud rate defaults */
|
||||||
|
#ifndef BAUD_RATE
|
||||||
|
#if F_CPU >= 8000000L
|
||||||
|
#define BAUD_RATE 115200L // Highest rate Avrdude win32 will support
|
||||||
|
#elsif F_CPU >= 1000000L
|
||||||
|
#define BAUD_RATE 9600L // 19200 also supported, but with significant error
|
||||||
|
#elsif F_CPU >= 128000L
|
||||||
|
#define BAUD_RATE 4800L // Good for 128kHz internal RC
|
||||||
|
#else
|
||||||
|
#define BAUD_RATE 1200L // Good even at 32768Hz
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Switch in soft UART for hard baud rates */
|
||||||
|
/*
|
||||||
|
* I don't understand what this was supposed to accomplish, where the
|
||||||
|
* constant "280" came from, or why automatically (and perhaps unexpectedly)
|
||||||
|
* switching to a soft uart is a good thing, so I'm undoing this in favor
|
||||||
|
* of a range check using the same calc used to config the BRG...
|
||||||
|
*/
|
||||||
|
#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
|
||||||
|
#ifndef SOFT_UART
|
||||||
|
#define SOFT_UART
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else // 0
|
||||||
|
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 > 250
|
||||||
|
#error Unachievable baud rate (too slow) BAUD_RATE
|
||||||
|
#endif // baud rate slow check
|
||||||
|
#if (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 < 3
|
||||||
|
#error Unachievable baud rate (too fast) BAUD_RATE
|
||||||
|
#endif // baud rate fastn check
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Watchdog settings */
|
||||||
|
#define WATCHDOG_OFF (0)
|
||||||
|
#define WATCHDOG_16MS (_BV(WDE))
|
||||||
|
#define WATCHDOG_32MS (_BV(WDP0) | _BV(WDE))
|
||||||
|
#define WATCHDOG_64MS (_BV(WDP1) | _BV(WDE))
|
||||||
|
#define WATCHDOG_125MS (_BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||||
|
#define WATCHDOG_250MS (_BV(WDP2) | _BV(WDE))
|
||||||
|
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
|
||||||
|
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
|
||||||
|
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
|
||||||
|
#ifndef __AVR_ATmega8__
|
||||||
|
#define WATCHDOG_4S (_BV(WDP3) | _BV(WDE))
|
||||||
|
#define WATCHDOG_8S (_BV(WDP3) | _BV(WDP0) | _BV(WDE))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function Prototypes */
|
||||||
|
/* The main function is in init9, which removes the interrupt vector table */
|
||||||
|
/* we don't need. It is also 'naked', which means the compiler does not */
|
||||||
|
/* generate any entry or exit code itself. */
|
||||||
|
int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9")));
|
||||||
|
void putch(char);
|
||||||
|
uint8_t getch(void);
|
||||||
|
static inline void getNch(uint8_t); /* "static inline" is a compiler hint to reduce code size */
|
||||||
|
void verifySpace();
|
||||||
|
static inline void flash_led(uint8_t);
|
||||||
|
uint8_t getLen();
|
||||||
|
static inline void watchdogReset();
|
||||||
|
void watchdogConfig(uint8_t x);
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
void uartDelay() __attribute__ ((naked));
|
||||||
|
#endif
|
||||||
|
void appStart() __attribute__ ((naked));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NRWW memory
|
||||||
|
* Addresses below NRWW (Non-Read-While-Write) can be programmed while
|
||||||
|
* continuing to run code from flash, slightly speeding up programming
|
||||||
|
* time. Beware that Atmel data sheets specify this as a WORD address,
|
||||||
|
* while optiboot will be comparing against a 16-bit byte address. This
|
||||||
|
* means that on a part with 128kB of memory, the upper part of the lower
|
||||||
|
* 64k will get NRWW processing as well, even though it doesn't need it.
|
||||||
|
* That's OK. In fact, you can disable the overlapping processing for
|
||||||
|
* a part entirely by setting NRWWSTART to zero. This reduces code
|
||||||
|
* space a bit, at the expense of being slightly slower, overall.
|
||||||
|
*
|
||||||
|
* RAMSTART should be self-explanatory. It's bigger on parts with a
|
||||||
|
* lot of peripheral registers.
|
||||||
|
*/
|
||||||
|
#if defined(__AVR_ATmega168__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0x3800)
|
||||||
|
#elif defined(__AVR_ATmega328P__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0x7000)
|
||||||
|
#elif defined (__AVR_ATmega644P__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0xE000)
|
||||||
|
#elif defined (__AVR_ATmega1284P__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0xE000)
|
||||||
|
#elif defined(__AVR_ATtiny84__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0x0000)
|
||||||
|
#elif defined(__AVR_ATmega1280__)
|
||||||
|
#define RAMSTART (0x200)
|
||||||
|
#define NRWWSTART (0xE000)
|
||||||
|
#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||||
|
#define RAMSTART (0x100)
|
||||||
|
#define NRWWSTART (0x1800)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* C zero initialises all global variables. However, that requires */
|
||||||
|
/* These definitions are NOT zero initialised, but that doesn't matter */
|
||||||
|
/* This allows us to drop the zero init code, saving us memory */
|
||||||
|
#define buff ((uint8_t*)(RAMSTART))
|
||||||
|
#ifdef VIRTUAL_BOOT_PARTITION
|
||||||
|
#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
|
||||||
|
#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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 uint16_t address = 0;
|
||||||
|
register uint8_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__");
|
||||||
|
#ifdef __AVR_ATmega8__
|
||||||
|
SP=RAMEND; // This is done by hardware reset
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Adaboot no-wait mod
|
||||||
|
ch = MCUSR;
|
||||||
|
MCUSR = 0;
|
||||||
|
if (!(ch & _BV(EXTRF))) appStart();
|
||||||
|
|
||||||
|
#if LED_START_FLASHES > 0
|
||||||
|
// Set up Timer 1 for timeout counter
|
||||||
|
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
|
||||||
|
#endif
|
||||||
|
#ifndef SOFT_UART
|
||||||
|
#ifdef __AVR_ATmega8__
|
||||||
|
UCSRA = _BV(U2X); //Double speed mode USART
|
||||||
|
UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx
|
||||||
|
UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1
|
||||||
|
UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||||
|
#else
|
||||||
|
UCSR0A = _BV(U2X0); //Double speed mode USART0
|
||||||
|
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
|
||||||
|
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
|
||||||
|
UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set up watchdog to trigger after 500ms
|
||||||
|
watchdogConfig(WATCHDOG_1S);
|
||||||
|
|
||||||
|
/* Set LED pin as output */
|
||||||
|
LED_DDR |= _BV(LED);
|
||||||
|
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
/* Set TX pin as output */
|
||||||
|
UART_DDR |= _BV(UART_TX_BIT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LED_START_FLASHES > 0
|
||||||
|
/* Flash onboard LED to signal entering of bootloader */
|
||||||
|
flash_led(LED_START_FLASHES * 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Forever loop */
|
||||||
|
for (;;) {
|
||||||
|
/* get character from UART */
|
||||||
|
ch = getch();
|
||||||
|
|
||||||
|
if(ch == STK_GET_PARAMETER) {
|
||||||
|
unsigned char which = getch();
|
||||||
|
verifySpace();
|
||||||
|
if (which == 0x82) {
|
||||||
|
/*
|
||||||
|
* Send optiboot version as "minor SW version"
|
||||||
|
*/
|
||||||
|
putch(OPTIBOOT_MINVER);
|
||||||
|
} else if (which == 0x81) {
|
||||||
|
putch(OPTIBOOT_MAJVER);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* GET PARAMETER returns a generic 0x03 reply for
|
||||||
|
* other parameters - enough to keep Avrdude happy
|
||||||
|
*/
|
||||||
|
putch(0x03);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(ch == STK_SET_DEVICE) {
|
||||||
|
// SET DEVICE is ignored
|
||||||
|
getNch(20);
|
||||||
|
}
|
||||||
|
else if(ch == STK_SET_DEVICE_EXT) {
|
||||||
|
// SET DEVICE EXT is ignored
|
||||||
|
getNch(5);
|
||||||
|
}
|
||||||
|
else if(ch == STK_LOAD_ADDRESS) {
|
||||||
|
// LOAD ADDRESS
|
||||||
|
uint16_t newAddress;
|
||||||
|
newAddress = getch();
|
||||||
|
newAddress = (newAddress & 0xff) | (getch() << 8);
|
||||||
|
#ifdef RAMPZ
|
||||||
|
// Transfer top bit to RAMPZ
|
||||||
|
RAMPZ = (newAddress & 0x8000) ? 1 : 0;
|
||||||
|
#endif
|
||||||
|
newAddress += newAddress; // Convert from word address to byte address
|
||||||
|
address = newAddress;
|
||||||
|
verifySpace();
|
||||||
|
}
|
||||||
|
else if(ch == STK_UNIVERSAL) {
|
||||||
|
// UNIVERSAL command is ignored
|
||||||
|
getNch(4);
|
||||||
|
putch(0x00);
|
||||||
|
}
|
||||||
|
/* Write memory, length is big endian and is in bytes */
|
||||||
|
else if(ch == STK_PROG_PAGE) {
|
||||||
|
// PROGRAM PAGE - we support flash programming only, not EEPROM
|
||||||
|
uint8_t *bufPtr;
|
||||||
|
uint16_t addrPtr;
|
||||||
|
|
||||||
|
getch(); /* getlen() */
|
||||||
|
length = getch();
|
||||||
|
getch();
|
||||||
|
|
||||||
|
// If we are in RWW section, immediately start page erase
|
||||||
|
if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||||
|
|
||||||
|
// While that is going on, read in page contents
|
||||||
|
bufPtr = buff;
|
||||||
|
do *bufPtr++ = getch();
|
||||||
|
while (--length);
|
||||||
|
|
||||||
|
// If we are in NRWW section, page erase has to be delayed until now.
|
||||||
|
// Todo: Take RAMPZ into account
|
||||||
|
if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
|
||||||
|
|
||||||
|
// Read command terminator, start reply
|
||||||
|
verifySpace();
|
||||||
|
|
||||||
|
// If only a partial page is to be programmed, the erase might not be complete.
|
||||||
|
// So check that here
|
||||||
|
boot_spm_busy_wait();
|
||||||
|
|
||||||
|
#ifdef VIRTUAL_BOOT_PARTITION
|
||||||
|
if ((uint16_t)(void*)address == 0) {
|
||||||
|
// This is the reset vector page. We need to live-patch the code so the
|
||||||
|
// bootloader runs.
|
||||||
|
//
|
||||||
|
// Move RESET vector to WDT vector
|
||||||
|
uint16_t vect = buff[0] | (buff[1]<<8);
|
||||||
|
rstVect = vect;
|
||||||
|
wdtVect = buff[8] | (buff[9]<<8);
|
||||||
|
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
|
||||||
|
buff[8] = vect & 0xff;
|
||||||
|
buff[9] = vect >> 8;
|
||||||
|
|
||||||
|
// Add jump to bootloader at RESET vector
|
||||||
|
buff[0] = 0x7f;
|
||||||
|
buff[1] = 0xce; // rjmp 0x1d00 instruction
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copy buffer into programming buffer
|
||||||
|
bufPtr = buff;
|
||||||
|
addrPtr = (uint16_t)(void*)address;
|
||||||
|
ch = SPM_PAGESIZE / 2;
|
||||||
|
do {
|
||||||
|
uint16_t a;
|
||||||
|
a = *bufPtr++;
|
||||||
|
a |= (*bufPtr++) << 8;
|
||||||
|
__boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
||||||
|
addrPtr += 2;
|
||||||
|
} while (--ch);
|
||||||
|
|
||||||
|
// Write from programming buffer
|
||||||
|
__boot_page_write_short((uint16_t)(void*)address);
|
||||||
|
boot_spm_busy_wait();
|
||||||
|
|
||||||
|
#if defined(RWWSRE)
|
||||||
|
// Reenable read access to flash
|
||||||
|
boot_rww_enable();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
/* Read memory block mode, length is big endian. */
|
||||||
|
else if(ch == STK_READ_PAGE) {
|
||||||
|
// READ PAGE - we only read flash
|
||||||
|
getch(); /* getlen() */
|
||||||
|
length = getch();
|
||||||
|
getch();
|
||||||
|
|
||||||
|
verifySpace();
|
||||||
|
#ifdef VIRTUAL_BOOT_PARTITION
|
||||||
|
do {
|
||||||
|
// Undo vector patch in bottom page so verify passes
|
||||||
|
if (address == 0) ch=rstVect & 0xff;
|
||||||
|
else if (address == 1) ch=rstVect >> 8;
|
||||||
|
else if (address == 8) ch=wdtVect & 0xff;
|
||||||
|
else if (address == 9) ch=wdtVect >> 8;
|
||||||
|
else ch = pgm_read_byte_near(address);
|
||||||
|
address++;
|
||||||
|
putch(ch);
|
||||||
|
} while (--length);
|
||||||
|
#else
|
||||||
|
#ifdef RAMPZ
|
||||||
|
// Since RAMPZ should already be set, we need to use EPLM directly.
|
||||||
|
// do putch(pgm_read_byte_near(address++));
|
||||||
|
// while (--length);
|
||||||
|
do {
|
||||||
|
uint8_t result;
|
||||||
|
__asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
|
||||||
|
putch(result);
|
||||||
|
address++;
|
||||||
|
}
|
||||||
|
while (--length);
|
||||||
|
#else
|
||||||
|
do putch(pgm_read_byte_near(address++));
|
||||||
|
while (--length);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get device signature bytes */
|
||||||
|
else if(ch == STK_READ_SIGN) {
|
||||||
|
// READ SIGN - return what Avrdude wants to hear
|
||||||
|
verifySpace();
|
||||||
|
putch(SIGNATURE_0);
|
||||||
|
putch(SIGNATURE_1);
|
||||||
|
putch(SIGNATURE_2);
|
||||||
|
}
|
||||||
|
else if (ch == STK_LEAVE_PROGMODE) { /* 'Q' */
|
||||||
|
// Adaboot no-wait mod
|
||||||
|
watchdogConfig(WATCHDOG_16MS);
|
||||||
|
verifySpace();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// This covers the response to commands like STK_ENTER_PROGMODE
|
||||||
|
verifySpace();
|
||||||
|
}
|
||||||
|
putch(STK_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void putch(char ch) {
|
||||||
|
#ifndef SOFT_UART
|
||||||
|
while (!(UCSR0A & _BV(UDRE0)));
|
||||||
|
UDR0 = ch;
|
||||||
|
#else
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
" com %[ch]\n" // ones complement, carry set
|
||||||
|
" sec\n"
|
||||||
|
"1: brcc 2f\n"
|
||||||
|
" cbi %[uartPort],%[uartBit]\n"
|
||||||
|
" rjmp 3f\n"
|
||||||
|
"2: sbi %[uartPort],%[uartBit]\n"
|
||||||
|
" nop\n"
|
||||||
|
"3: rcall uartDelay\n"
|
||||||
|
" rcall uartDelay\n"
|
||||||
|
" lsr %[ch]\n"
|
||||||
|
" dec %[bitcnt]\n"
|
||||||
|
" brne 1b\n"
|
||||||
|
:
|
||||||
|
:
|
||||||
|
[bitcnt] "d" (10),
|
||||||
|
[ch] "r" (ch),
|
||||||
|
[uartPort] "I" (_SFR_IO_ADDR(UART_PORT)),
|
||||||
|
[uartBit] "I" (UART_TX_BIT)
|
||||||
|
:
|
||||||
|
"r25"
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getch(void) {
|
||||||
|
uint8_t ch;
|
||||||
|
|
||||||
|
#ifdef LED_DATA_FLASH
|
||||||
|
#ifdef __AVR_ATmega8__
|
||||||
|
LED_PORT ^= _BV(LED);
|
||||||
|
#else
|
||||||
|
LED_PIN |= _BV(LED);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"1: sbic %[uartPin],%[uartBit]\n" // Wait for start edge
|
||||||
|
" rjmp 1b\n"
|
||||||
|
" rcall uartDelay\n" // Get to middle of start bit
|
||||||
|
"2: rcall uartDelay\n" // Wait 1 bit period
|
||||||
|
" rcall uartDelay\n" // Wait 1 bit period
|
||||||
|
" clc\n"
|
||||||
|
" sbic %[uartPin],%[uartBit]\n"
|
||||||
|
" sec\n"
|
||||||
|
" dec %[bitCnt]\n"
|
||||||
|
" breq 3f\n"
|
||||||
|
" ror %[ch]\n"
|
||||||
|
" rjmp 2b\n"
|
||||||
|
"3:\n"
|
||||||
|
:
|
||||||
|
[ch] "=r" (ch)
|
||||||
|
:
|
||||||
|
[bitCnt] "d" (9),
|
||||||
|
[uartPin] "I" (_SFR_IO_ADDR(UART_PIN)),
|
||||||
|
[uartBit] "I" (UART_RX_BIT)
|
||||||
|
:
|
||||||
|
"r25"
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
while(!(UCSR0A & _BV(RXC0)))
|
||||||
|
;
|
||||||
|
if (!(UCSR0A & _BV(FE0))) {
|
||||||
|
/*
|
||||||
|
* A Framing Error indicates (probably) that something is talking
|
||||||
|
* to us at the wrong bit rate. Assume that this is because it
|
||||||
|
* expects to be talking to the application, and DON'T reset the
|
||||||
|
* watchdog. This should cause the bootloader to abort and run
|
||||||
|
* the application "soon", if it keeps happening. (Note that we
|
||||||
|
* don't care that an invalid char is returned...)
|
||||||
|
*/
|
||||||
|
watchdogReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = UDR0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LED_DATA_FLASH
|
||||||
|
#ifdef __AVR_ATmega8__
|
||||||
|
LED_PORT ^= _BV(LED);
|
||||||
|
#else
|
||||||
|
LED_PIN |= _BV(LED);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
// AVR305 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
|
||||||
|
// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
|
||||||
|
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
|
||||||
|
#if UART_B_VALUE > 255
|
||||||
|
#error Baud rate too slow for soft UART
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void uartDelay() {
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"ldi r25,%[count]\n"
|
||||||
|
"1:dec r25\n"
|
||||||
|
"brne 1b\n"
|
||||||
|
"ret\n"
|
||||||
|
::[count] "M" (UART_B_VALUE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void getNch(uint8_t count) {
|
||||||
|
do getch(); while (--count);
|
||||||
|
verifySpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
void verifySpace() {
|
||||||
|
if (getch() != CRC_EOP) {
|
||||||
|
watchdogConfig(WATCHDOG_16MS); // shorten WD timeout
|
||||||
|
while (1) // and busy-loop so that WD causes
|
||||||
|
; // a reset and app start.
|
||||||
|
}
|
||||||
|
putch(STK_INSYNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LED_START_FLASHES > 0
|
||||||
|
void flash_led(uint8_t count) {
|
||||||
|
do {
|
||||||
|
TCNT1 = -(F_CPU/(1024*16));
|
||||||
|
TIFR1 = _BV(TOV1);
|
||||||
|
while(!(TIFR1 & _BV(TOV1)));
|
||||||
|
#ifdef __AVR_ATmega8__
|
||||||
|
LED_PORT ^= _BV(LED);
|
||||||
|
#else
|
||||||
|
LED_PIN |= _BV(LED);
|
||||||
|
#endif
|
||||||
|
watchdogReset();
|
||||||
|
} while (--count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Watchdog functions. These are only safe with interrupts turned off.
|
||||||
|
void watchdogReset() {
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"wdr\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void watchdogConfig(uint8_t x) {
|
||||||
|
WDTCSR = _BV(WDCE) | _BV(WDE);
|
||||||
|
WDTCSR = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void appStart() {
|
||||||
|
watchdogConfig(WATCHDOG_OFF);
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
#ifdef VIRTUAL_BOOT_PARTITION
|
||||||
|
// Jump to WDT vector
|
||||||
|
"ldi r30,4\n"
|
||||||
|
"clr r31\n"
|
||||||
|
#else
|
||||||
|
// Jump to RST vector
|
||||||
|
"clr r30\n"
|
||||||
|
"clr r31\n"
|
||||||
|
#endif
|
||||||
|
"ijmp\n"
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
:020000021000EC
|
||||||
|
:10FE00000F92CDB7DEB7112484B714BE81FFDFD0C7
|
||||||
|
:10FE100082E08093C00088E18093C10086E08093F7
|
||||||
|
:10FE2000C2008AE28093C4008EE0BBD0209A00E03A
|
||||||
|
:10FE300010E0EE24E394E1E1DE2EF3E0FF2EA5D006
|
||||||
|
:10FE4000813471F4A2D08983B2D08981823809F4D7
|
||||||
|
:10FE50008BC0813811F484E001C083E08FD08BC067
|
||||||
|
:10FE6000823411F484E103C0853419F485E0A7D00D
|
||||||
|
:10FE700082C0853591F489D0A82EBB2486D0082F66
|
||||||
|
:10FE800010E0102F00270A291B29812F881F88279F
|
||||||
|
:10FE9000881F8BBF000F111F6DC0863521F484E0D1
|
||||||
|
:10FEA0008ED080E0DBCF843609F040C06ED06DD0BC
|
||||||
|
:10FEB000C82E6BD080EE0030180718F4F801F7BE9A
|
||||||
|
:10FEC000E895A12C51E0B52E60D0F50181935F013A
|
||||||
|
:10FED000CE16D1F7F0EE00301F0718F0F801F7BE8C
|
||||||
|
:10FEE000E89565D007B600FCFDCFF801A0E0B1E0D1
|
||||||
|
:10FEF0002C9130E011968C91119790E0982F8827E3
|
||||||
|
:10FF0000822B932B12960C01E7BEE89511243296B2
|
||||||
|
:10FF100082E0A030B80761F785E0F80187BFE89577
|
||||||
|
:10FF200007B600FCFDCFD7BEE89525C08437A9F4FD
|
||||||
|
:10FF30002CD02BD0B82E29D03AD0CB2C4801F401AC
|
||||||
|
:10FF400086911CD00894811C911CCA94C1F70F5F44
|
||||||
|
:10FF50001F4FBA940B0D111D0EC0853739F427D0F1
|
||||||
|
:10FF60008EE10CD087E90AD085E078CF813511F495
|
||||||
|
:10FF700088E017D01CD080E101D061CF9091C00003
|
||||||
|
:10FF800095FFFCCF8093C60008958091C00087FF45
|
||||||
|
:10FF9000FCCF8091C00084FD01C0A8958091C6006F
|
||||||
|
:10FFA0000895E0E6F0E098E1908380830895EDDF26
|
||||||
|
:10FFB000803219F088E0F5DFFFCF84E1DFCFCF9307
|
||||||
|
:10FFC000C82FE3DFC150E9F7F2DFCF91089580E059
|
||||||
|
:08FFD000E8DFEE27FF2709948A
|
||||||
|
:040000031000FE00EB
|
||||||
|
:00000001FF
|
|
@ -0,0 +1,81 @@
|
||||||
|
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
|
||||||
|
/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
|
||||||
|
#define LED_DDR DDRB
|
||||||
|
#define LED_PORT PORTB
|
||||||
|
#define LED_PIN PINB
|
||||||
|
#define LED PINB5
|
||||||
|
|
||||||
|
/* Ports for soft UART */
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
#define UART_PORT PORTD
|
||||||
|
#define UART_PIN PIND
|
||||||
|
#define UART_DDR DDRD
|
||||||
|
#define UART_TX_BIT 1
|
||||||
|
#define UART_RX_BIT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__AVR_ATmega8__)
|
||||||
|
//Name conversion R.Wiersma
|
||||||
|
#define UCSR0A UCSRA
|
||||||
|
#define UDR0 UDR
|
||||||
|
#define UDRE0 UDRE
|
||||||
|
#define RXC0 RXC
|
||||||
|
#define FE0 FE
|
||||||
|
#define TIFR1 TIFR
|
||||||
|
#define WDTCSR WDTCR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Luminet support */
|
||||||
|
#if defined(__AVR_ATtiny84__)
|
||||||
|
/* Red LED is connected to pin PA4 */
|
||||||
|
#define LED_DDR DDRA
|
||||||
|
#define LED_PORT PORTA
|
||||||
|
#define LED_PIN PINA
|
||||||
|
#define LED PINA4
|
||||||
|
/* Ports for soft UART - left port only for now. TX/RX on PA2/PA3 */
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
#define UART_PORT PORTA
|
||||||
|
#define UART_PIN PINA
|
||||||
|
#define UART_DDR DDRA
|
||||||
|
#define UART_TX_BIT 2
|
||||||
|
#define UART_RX_BIT 3
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sanguino support */
|
||||||
|
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
|
||||||
|
/* Onboard LED is connected to pin PB0 on Sanguino */
|
||||||
|
#define LED_DDR DDRB
|
||||||
|
#define LED_PORT PORTB
|
||||||
|
#define LED_PIN PINB
|
||||||
|
#define LED PINB0
|
||||||
|
|
||||||
|
/* Ports for soft UART */
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
#define UART_PORT PORTD
|
||||||
|
#define UART_PIN PIND
|
||||||
|
#define UART_DDR DDRD
|
||||||
|
#define UART_TX_BIT 1
|
||||||
|
#define UART_RX_BIT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Mega support */
|
||||||
|
#if defined(__AVR_ATmega1280__)
|
||||||
|
/* Onboard LED is connected to pin PB7 on Arduino Mega */
|
||||||
|
#define LED_DDR DDRB
|
||||||
|
#define LED_PORT PORTB
|
||||||
|
#define LED_PIN PINB
|
||||||
|
#define LED PINB7
|
||||||
|
|
||||||
|
/* Ports for soft UART */
|
||||||
|
#ifdef SOFT_UART
|
||||||
|
#define UART_PORT PORTE
|
||||||
|
#define UART_PIN PINE
|
||||||
|
#define UART_DDR DDRE
|
||||||
|
#define UART_TX_BIT 1
|
||||||
|
#define UART_RX_BIT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* STK500 constants list, from AVRDUDE */
|
||||||
|
#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'
|
Reference in a new issue