diff options
author | Bluebie <a@creativepony.com> | 2012-10-04 11:26:39 +1000 |
---|---|---|
committer | Bluebie <a@creativepony.com> | 2012-10-04 11:26:39 +1000 |
commit | 81ff282291527178abab4ab63b22065d6eb3cb2f (patch) | |
tree | 7d80a9b0de87412fa2d3d53646b26d9c85ec6de2 /upgrade | |
parent | c4918723c476db48c53cafe0b5373223cd1cca04 (diff) | |
download | micronucleus-81ff282291527178abab4ab63b22065d6eb3cb2f.tar.gz micronucleus-81ff282291527178abab4ab63b22065d6eb3cb2f.tar.bz2 micronucleus-81ff282291527178abab4ab63b22065d6eb3cb2f.zip |
Added viral in place upgrader tool, to upgrade bootloaders via the bootloader itself (should work with any attiny85 bootloader I think, in either direction)
Diffstat (limited to 'upgrade')
-rw-r--r-- | upgrade/Makefile | 204 | ||||
-rw-r--r-- | upgrade/bootloader_data.c | 9 | ||||
-rw-r--r-- | upgrade/generate-data.rb | 34 | ||||
-rw-r--r-- | upgrade/readme.txt | 15 | ||||
-rw-r--r-- | upgrade/releases/micronucleus-1.03-upgrade.hex | 177 | ||||
-rw-r--r-- | upgrade/upgrade.c | 165 | ||||
-rw-r--r-- | upgrade/utils.h | 90 |
7 files changed, 694 insertions, 0 deletions
diff --git a/upgrade/Makefile b/upgrade/Makefile new file mode 100644 index 0000000..e4f6b9d --- /dev/null +++ b/upgrade/Makefile @@ -0,0 +1,204 @@ +# Name: Makefile +# Project: Upgrade - based on Micronucleus makefile +# Author: Jenna Fox; portions by Christian Starkjohann, Louis Beaudoin +# Creation Date: 2012-10-4 +# Tabsize: 4 +# License: GNU GPL v2 (see License.txt) + +############################################################################### +# Configure the following variables according to your AVR. +# Program the device with +# make fuse # to set the clock generator, boot section size etc. +# make flash # to load the boot loader into flash +# make lock # to protect the boot loader from overwriting +# make disablereset # for ATtiny85 target - to use external reset line for IO (CAUTION: this is not easy to enable again, see README) + +F_CPU = 16500000 +DEVICE = attiny85 +FUSEOPT = $(FUSEOPT_t85) +LOCKOPT = -U lock:w:0x2f:m + +# app starts at beginning, as it should! +APP_ADDRESS = 0 + +PROGRAMMER = -c USBasp +# PROGRAMMER contains AVRDUDE options to address your programmer + +FUSEOPT_8 = -U hfuse:w:0xc0:m -U lfuse:w:0x9f:m +FUSEOPT_88 = -U hfuse:w:0xd6:m -U lfuse:w:0xdf:m -U efuse:w:0x00:m +FUSEOPT_168 = -U hfuse:w:0xd6:m -U lfuse:w:0xdf:m -U efuse:w:0x00:m +FUSEOPT_328 = -U lfuse:w:0xf7:m -U hfuse:w:0xda:m -U efuse:w:0x03:m +FUSEOPT_t85 = -U lfuse:w:0xe1:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m +FUSEOPT_t85_DISABLERESET = -U lfuse:w:0xe1:m -U efuse:w:0xfe:m -U hfuse:w:0x5d:m +# You may have to change the order of these -U commands. + +#--------------------------------------------------------------------- +# ATMega8 +#--------------------------------------------------------------------- +# Fuse high byte: +# 0xc0 = 1 1 0 0 0 0 0 0 <-- BOOTRST (boot reset vector at 0x1800) +# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0 +# | | | | | +-------- BOOTSZ1 +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- CKOPT (full output swing) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ WDTON (WDT not always on) +# +-------------------- RSTDISBL (reset pin is enabled) +# Fuse low byte: +# 0x9f = 1 0 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ BODEN (BrownOut Detector enabled) +# +-------------------- BODLEVEL (2.7V) +#--------------------------------------------------------------------- +# ATMega88, ATMega168 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0x00 = 0 0 0 0 0 0 0 0 <-- BOOTRST (boot reset vector at 0x1800) +# \+/ +# +------- BOOTSZ (00 = 2k bytes) +# Fuse high byte: +# 0xd6 = 1 1 0 1 0 1 1 0 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) +# | | | | + --------- EESAVE (preserve EEPROM over chip erase) +# | | | +-------------- WDTON (if 0: watchdog always on) +# | | +---------------- SPIEN (allow serial programming) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (reset pin is enabled) +# Fuse low byte: +# 0xdf = 1 1 0 1 1 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (external >8M crystal) +# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) +# | +------------------ CKOUT (if 0: Clock output enabled) +# +-------------------- CKDIV8 (if 0: divide by 8) +#--------------------------------------------------------------------- +# ATMega328P +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0x03 = - - - - - 0 1 1 +# \-+-/ +# +------ BODLEVEL 0..2 (011 = 4.3V) +# Fuse high byte: +# 0xda = 1 1 0 1 1 0 1 0 <-- BOOTRST (0 = jump to bootloader at start) +# ^ ^ ^ ^ ^ \+/ +# | | | | | +------- BOOTSZ 0..1 (01 = 2KB starting at 0x7800) +# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase) +# | | | +-------------- WDTON (1 = watchdog disabled at start) +# | | +---------------- SPIEN (0 = allow serial programming) +# | +------------------ DWEN (1 = debug wire disable) +# +-------------------- RSTDISBL (1 = reset pin is enabled) +# Fuse low byte: +# 0xf7 = 1 1 1 1 0 1 1 1 +# ^ ^ \ / \--+--/ +# | | | +------- CKSEL 3..0 (0111 = external full-swing crystal) +# | | +--------------- SUT 1..0 (11 = startup time 16K CK/14K + 65ms) +# | +------------------ CKOUT (1 = clock output disabled) +# +-------------------- CKDIV8 (1 = do not divide clock by 8) +#--------------------------------------------------------------------- +# ATtiny85 +#--------------------------------------------------------------------- +# Fuse extended byte: +# 0xFE = - - - - - 1 1 0 +# ^ +# | +# +---- SELFPRGEN (enable self programming flash) +# +# Fuse high byte: +# 0xdd = 1 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> enabled) +# +# Fuse high byte ("no reset": external reset disabled, can't program through SPI anymore) +# 0x5d = 0 1 0 1 1 1 0 1 +# ^ ^ ^ ^ ^ \-+-/ +# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) +# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) +# | | | +-------------- WDTON (watchdog timer always on -> disable) +# | | +---------------- SPIEN (enable serial programming -> enabled) +# | +------------------ DWEN (debug wire enable) +# +-------------------- RSTDISBL (disable external reset -> disabled!) +# +# Fuse low byte: +# 0xe1 = 1 1 1 0 0 0 0 1 +# ^ ^ \+/ \--+--/ +# | | | +------- CKSEL 3..0 (clock selection -> HF PLL) +# | | +--------------- SUT 1..0 (BOD enabled, fast rising power) +# | +------------------ CKOUT (clock output on CKOUT pin -> disabled) +# +-------------------- CKDIV8 (divide clock by 8 -> don't divide) + +############################################################################### + +# Tools: +AVRDUDE = avrdude $(PROGRAMMER) -p $(DEVICE) +CC = avr-gcc + +# Options: +DEFINES = -DAPP_ADDRESS=0x$(APP_ADDRESS) #-DDEBUG_LEVEL=2 +# Remove the -fno-* options when you use gcc 3, it does not understand them +CFLAGS = -Wall -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -I. -Ilibs-device -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES) +LDFLAGS = -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(APP_ADDRESS),-Map=upgrade.map + +OBJECTS = upgrade.o + +# symbolic targets: +all: upgrade.hex + + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ -Wa,-ahls=$<.lst + +.S.o: + $(CC) $(CFLAGS) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +.c.s: + $(CC) $(CFLAGS) -S $< -o $@ + +flash: all + $(AVRDUDE) -U flash:w:upgrade.hex:i + +readflash: + $(AVRDUDE) -U flash:r:read.hex:i + +fuse: + $(AVRDUDE) $(FUSEOPT) + +disablereset: + $(AVRDUDE) $(FUSEOPT_t85_DISABLERESET) + +lock: + $(AVRDUDE) $(LOCKOPT) + +read_fuses: + $(UISP) --rd_fuses + +clean: + rm -f upgrade.hex upgrade.bin *.o upgrade.s upgrade.map upgrade.c.lst + +# file targets: +upgrade.bin: $(OBJECTS) + $(CC) $(CFLAGS) -o upgrade.bin $(OBJECTS) $(LDFLAGS) + +upgrade.hex: upgrade.bin + rm -f upgrade.hex upgrade.eep.hex + avr-objcopy -j .text -j .data -O ihex upgrade.bin upgrade.hex + avr-size upgrade.hex + +disasm: upgrade.bin + avr-objdump -d upgrade.bin + +cpp: + $(CC) $(CFLAGS) -E upgrade.c + + diff --git a/upgrade/bootloader_data.c b/upgrade/bootloader_data.c new file mode 100644 index 0000000..f0b06c2 --- /dev/null +++ b/upgrade/bootloader_data.c @@ -0,0 +1,9 @@ +// This file contains the bootloader data itself and the address to install the bootloader at +// Use generate-data.rb with ruby 1.9 to generate these values from a hex file +// Generated from ../firmware/releases/tiny85/micronucleus-1.03.hex at 2012-10-04 11:12:26 +1000 + +uint16_t bootloader_data[1032] PROGMEM = { +0xc022, 0xc040, 0xc06c, 0xc03e, 0xc03d, 0xc03c, 0xc03b, 0xc03a, 0xc039, 0xc038, 0xc037, 0xc036, 0xc035, 0xc034, 0xc033, 0x0304, 0x0409, 0x0112, 0x0110, 0x00ff, 0x0800, 0x16d0, 0x0753, 0x0103, 0x0000, 0x0100, 0x0209, 0x0012, 0x0101, 0x8000, 0x0932, 0x0004, 0x0000, 0x0000, 0x0000, 0x2411, 0xbe1f, 0xe5cf, 0xe0d2, 0xbfde, 0xbfcd, 0xeb00, 0x930f, 0xe007, 0x930f, 0xe010, 0xe6a0, 0xe0b0, 0xecea, 0xe1ff, 0xc002, 0x9005, 0x920d, 0x36a6, 0x07b1, 0xf7d9, 0xe010, 0xe6a6, 0xe0b0, 0xc001, 0x921d, 0x39aa, 0x07b1, 0xf7e1, 0xd1df, 0xc3c1, 0xcfbd, 0x2fa8, 0x2fb9, 0xe080, 0xe090, 0xe041, 0xea50, 0x9560, 0xe030, 0xc009, 0x912d, 0x2782, 0x9597, 0x9587, 0xf010, 0x2784, 0x2795, 0x5e30, 0xf3c8, 0x5f6f, 0xf3a8, 0x9508, 0xdfea, 0x938d, 0x939d, 0x9508, 0xe0a6, 0x2788, 0x2799, 0x95aa, 0xf069, 0x9701, 0xf3e1, 0x99b3, 0xcffc, 0x9bb3, 0xcffe, 0xe081, 0x2799, 0xb3a6, 0x9601, 0xf011, 0x71a8, 0xf7d9, 0x9508, 0x93cf, 0xb7cf, 0x93cf, 0x91c0, 0x025f, 0x3bc0, 0xf421, 0x91c0, 0x025e, 0x30c7, 0xf021, 0x91cf, 0xbfcf, 0x91cf, 0xcf81, 0x27cc, 0x95c3, 0x9bb3, 0xf7e9, 0x9bb3, 0xc00b, 0x9bb3, 0xc009, 0x9bb3, 0xc007, 0x9bb3, 0xc005, 0x9bb3, 0xc003, 0x9bb3, 0xc001, 0xc0d3, 0x920f, 0x93df, 0x91c0, 0x007d, 0x27dd, 0x57cc, 0x4fdf, 0x2e01, 0x9bb3, 0xc003, 0x91df, 0x900f, 0xcfe6, 0x932f, 0x930f, 0x931f, 0x934f, 0xef2f, 0x6f4f, 0xb306, 0xfb03, 0xf920, 0x935f, 0x933f, 0xe050, 0xe03b, 0xc065, 0xb316, 0x2601, 0x2950, 0xfd53, 0x95c8, 0xb356, 0x2701, 0xfb03, 0xf925, 0x732f, 0xb306, 0xf0b1, 0x2750, 0x2710, 0xfb13, 0xf926, 0xb206, 0x3022, 0xf0f0, 0xc000, 0xb316, 0x2701, 0xfb03, 0xf927, 0x2601, 0x2950, 0xb206, 0x3024, 0xf5e8, 0x774f, 0x6820, 0xb316, 0x0000, 0xcff6, 0x2750, 0x7d4f, 0x6220, 0xb206, 0x2f10, 0x0000, 0xc000, 0xb306, 0x2600, 0x2950, 0x2710, 0xfb13, 0xf926, 0xb206, 0xcfe2, 0x7b4f, 0xb306, 0x6420, 0xc000, 0xcfda, 0x2601, 0x2950, 0x7118, 0xb206, 0xf169, 0x7f4e, 0x6021, 0x2f01, 0xb316, 0xc028, 0x2600, 0x2950, 0x7f4d, 0xb206, 0x6022, 0x2f10, 0xc029, 0x2601, 0x2950, 0x7f4b, 0xb206, 0x6024, 0x2f01, 0xc02d, 0xb316, 0x2601, 0x2950, 0x7f47, 0x6028, 0x0000, 0xb206, 0xc02e, 0x7e4f, 0xb306, 0x6120, 0xc030, 0x2742, 0xb306, 0x9349, 0x2600, 0x2950, 0x2710, 0xb206, 0xef4f, 0xfb13, 0xf920, 0x7f29, 0xb316, 0xf279, 0x7118, 0xf159, 0x2601, 0x2950, 0xb206, 0x2701, 0xfb03, 0xf921, 0x7f23, 0xb306, 0xf271, 0x2600, 0x2950, 0x5031, 0xf0d0, 0xb206, 0x2710, 0xfb13, 0xf922, 0x7e27, 0xb316, 0xf251, 0x2601, 0x2950, 0x2701, 0xfb03, 0xb206, 0xf923, 0x7c2f, 0xf249, 0x0000, 0xb306, 0x2710, 0xfb13, 0xf924, 0x2600, 0x2950, 0xb206, 0x792f, 0xf239, 0xcf70, 0xe210, 0xbf1a, 0x2700, 0xc017, 0x503b, 0x9531, 0x1bc3, 0x40d0, 0xe210, 0xbf1a, 0x8108, 0x3c03, 0xf0f9, 0x340b, 0xf0e9, 0x9120, 0x007b, 0x8119, 0x0f11, 0x1312, 0xcfed, 0x3609, 0xf151, 0x320d, 0xf011, 0x3e01, 0xf739, 0x9300, 0x0082, 0x913f, 0x915f, 0x914f, 0x911f, 0x910f, 0x912f, 0x91df, 0x900f, 0xb7ca, 0xfdc5, 0xcf1d, 0x91cf, 0xbfcf, 0x91cf, 0x9518, 0x9120, 0x0082, 0x2322, 0xf369, 0x9110, 0x0080, 0x2311, 0xf521, 0x3034, 0xf122, 0x9330, 0x0080, 0x9320, 0x007c, 0x9110, 0x007d, 0xe03b, 0x1b31, 0x9330, 0x007d, 0xc019, 0x9100, 0x0080, 0x3001, 0xf49c, 0xe50a, 0x9130, 0x0060, 0xfd34, 0xc011, 0x9300, 0x0060, 0xe7c0, 0xe0d0, 0xc010, 0x2705, 0xe010, 0xc000, 0xc021, 0x2705, 0xe010, 0x95c8, 0xbb08, 0xc014, 0xe53a, 0xc001, 0xed32, 0x2e03, 0xe0c0, 0xe0d0, 0xe032, 0xb317, 0x6118, 0x9ac3, 0xb308, 0xbb17, 0xe158, 0xe820, 0xef4f, 0xff20, 0x2705, 0xbb08, 0x9527, 0x9517, 0x3f1c, 0xf728, 0x0000, 0x5245, 0xf7b0, 0xff20, 0x2705, 0x9527, 0xbb08, 0x9517, 0x3f1c, 0xf6b8, 0x9129, 0x953a, 0xf761, 0x7e07, 0x9110, 0x0081, 0x0f11, 0xbb08, 0x50c2, 0x40d0, 0xf011, 0x9310, 0x007b, 0xe210, 0xbf1a, 0x6008, 0xb317, 0x7e17, 0x2f40, 0x7e47, 0xe054, 0x955a, 0xf7f1, 0xbb08, 0xbb17, 0xbb48, 0xcf8a, 0xe081, 0x9380, 0x0067, 0x94f8, 0x91e0, 0x006e, 0x91f0, 0x006f, 0x9732, 0xe085, 0x9380, 0x0057, 0x95e8, 0xb607, 0xfc00, 0xcffd, 0x9478, 0x9508, 0x019c, 0x91e0, 0x006e, 0x91f0, 0x006f, 0x9730, 0xf149, 0x30e4, 0x05f1, 0xf0b1, 0xe187, 0x3bec, 0x07f8, 0xf439, 0x9120, 0x006a, 0x9130, 0x006b, 0x5d2e, 0x4f3b, 0xc00d, 0xe187, 0x3bee, 0x07f8, 0xf449, 0x9120, 0x006c, 0x9130, 0x006d, 0x5d2d, 0x4f3b, 0xc002, 0xed2f, 0xec3b, 0x94f8, 0xe081, 0x0109, 0x9380, 0x0057, 0x95e8, 0x2411, 0x9478, 0x9632, 0x93f0, 0x006f, 0x93e0, 0x006e, 0x9508, 0xe181, 0x9380, 0x0057, 0x95e8, 0xcfeb, 0xef8f, 0xef9f, 0xdfc8, 0x9180, 0x006e, 0x9190, 0x006f, 0x738f, 0x7090, 0x2b89, 0xf7a9, 0xcfad, 0xe188, 0xb60f, 0x94f8, 0xbd81, 0xbc11, 0xbe0f, 0xe0e0, 0xe0f0, 0x9185, 0x9194, 0x5d8f, 0x4c9b, 0xf439, 0xe0e4, 0xe0f0, 0x9185, 0x9194, 0x5d8f, 0x4c9b, 0xf009, 0xdfdf, 0x9210, 0x006f, 0x9210, 0x006e, 0x9aac, 0xb78b, 0x6280, 0xbf8b, 0x9abb, 0xe888, 0xe193, 0xe9ec, 0xe0f1, 0x9731, 0xf7f1, 0x9701, 0xf7d1, 0x98bb, 0x9478, 0x24ee, 0x24ff, 0x9110, 0x0080, 0x5013, 0xfd17, 0xc0d0, 0x9180, 0x007d, 0xe0cc, 0xe0d0, 0x1bc8, 0x09d1, 0x57cc, 0x4fdf, 0x9180, 0x007c, 0x328d, 0xf009, 0xc08d, 0x3018, 0xf009, 0xc0be, 0xec83, 0x9380, 0x0070, 0xe58a, 0x9380, 0x0060, 0x9210, 0x0069, 0x8128, 0x2f82, 0x7680, 0x8199, 0x2388, 0xf109, 0x2399, 0xf441, 0xe682, 0xe090, 0x9390, 0x007f, 0x9380, 0x007e, 0xe024, 0xc068, 0x3091, 0xf451, 0x818c, 0x819d, 0x9390, 0x006f, 0x9380, 0x006e, 0xfd27, 0xc059, 0xef9f, 0xc058, 0x9180, 0x0066, 0x3092, 0xf411, 0x6081, 0xc001, 0x6084, 0x9380, 0x0066, 0xe020, 0xc051, 0x818a, 0x9210, 0x0079, 0x2399, 0xf431, 0x9210, 0x007a, 0xe789, 0xe090, 0xe022, 0xc03c, 0x3095, 0xf419, 0x9380, 0x0081, 0xc034, 0x3096, 0xf511, 0x818b, 0x3081, 0xf419, 0xee82, 0xe197, 0xc004, 0x3082, 0xf441, 0xef84, 0xe197, 0x9390, 0x007f, 0x9380, 0x007e, 0xe122, 0xc00e, 0x3083, 0xf459, 0x818a, 0x2388, 0xf441, 0xed8e, 0xe197, 0x9390, 0x007f, 0x9380, 0x007e, 0xe024, 0xc001, 0xe020, 0xe480, 0x9380, 0x0069, 0xc01d, 0x3098, 0xf419, 0xe883, 0xe090, 0xc009, 0x3099, 0xf419, 0x9380, 0x0083, 0xc006, 0x309a, 0xf421, 0xe789, 0xe090, 0xe021, 0xc003, 0xe789, 0xe090, 0xe020, 0x9390, 0x007f, 0x9380, 0x007e, 0xc005, 0x819e, 0xe880, 0x9380, 0x0069, 0xc007, 0x818f, 0x2388, 0xf419, 0x819e, 0x1792, 0xf008, 0x2f92, 0x9390, 0x0061, 0xc034, 0x9180, 0x0069, 0xff87, 0xc030, 0x9180, 0x006e, 0x9190, 0x006f, 0x9700, 0xf439, 0x8188, 0x8199, 0x9390, 0x006b, 0x9380, 0x006a, 0xc00d, 0x3084, 0x0591, 0xf439, 0x8188, 0x8199, 0x9390, 0x006d, 0x9380, 0x006c, 0xc003, 0x5c80, 0x4197, 0xf438, 0x8188, 0x8199, 0xded5, 0x5012, 0xf011, 0x9622, 0xcfdf, 0x9180, 0x006e, 0x9190, 0x006f, 0x738f, 0x7090, 0x2b89, 0xf439, 0x9180, 0x0066, 0x6082, 0x9380, 0x0066, 0x9210, 0x0061, 0x9210, 0x0080, 0x9180, 0x0060, 0xff84, 0xc03c, 0x9180, 0x0061, 0x3f8f, 0xf1c1, 0x2f18, 0x3089, 0xf008, 0xe018, 0x1b81, 0x9380, 0x0061, 0x9180, 0x0070, 0xe898, 0x2789, 0x9380, 0x0070, 0x2311, 0xf0e1, 0x91e0, 0x007e, 0x91f0, 0x007f, 0x9180, 0x0069, 0xff86, 0xc009, 0x2f91, 0xe7a1, 0xe0b0, 0x9184, 0x938d, 0x9631, 0x5091, 0xf7d9, 0xc007, 0x2f91, 0xe7a1, 0xe0b0, 0x9181, 0x938d, 0x5091, 0xf7e1, 0x93f0, 0x007f, 0x93e0, 0x007e, 0xe781, 0xe090, 0x2f61, 0xdd02, 0x2f61, 0x5f6c, 0x306c, 0xf019, 0xef8f, 0x9380, 0x0061, 0x9360, 0x0060, 0xe194, 0xb386, 0x7188, 0xf431, 0x5091, 0xf7d9, 0x9210, 0x0081, 0x9210, 0x007b, 0xe010, 0x2399, 0xf409, 0xe011, 0x9180, 0x0068, 0x1781, 0xf039, 0x2311, 0xf419, 0x94f8, 0xd04f, 0x9478, 0x9310, 0x0068, 0xe98c, 0xe091, 0x9701, 0xf7f1, 0x9180, 0x0066, 0x2388, 0xf019, 0x24ee, 0x24ff, 0xc003, 0x9408, 0x1ce1, 0x1cf1, 0x2f18, 0xff80, 0xc014, 0x94f8, 0xece0, 0xe1f7, 0x54e0, 0x40f0, 0xe083, 0x9380, 0x0057, 0x95e8, 0xb607, 0xfc00, 0xcffd, 0x9730, 0xf7a9, 0x9210, 0x006f, 0x9210, 0x006e, 0xde78, 0x9478, 0xff11, 0xc00f, 0xe38a, 0xe290, 0x9701, 0xf7f1, 0x9180, 0x006e, 0x9190, 0x006f, 0x738f, 0x7090, 0x2b89, 0xf011, 0xde68, 0xc001, 0xde1f, 0xfd12, 0xc008, 0x9210, 0x0066, 0xe580, 0x16e8, 0xec83, 0x06f8, 0xf408, 0xce92, 0xe282, 0xea91, 0x9701, 0xf7f1, 0x94f8, 0xbe1b, 0xba15, 0x9210, 0x025f, 0x9210, 0x025e, 0xcc3a, 0x92ff, 0x930f, 0x931f, 0x93cf, 0x93df, 0xe880, 0x2ef8, 0xe000, 0xe0c0, 0xe0d0, 0x2f10, 0x0d1f, 0xbf11, 0xdc8a, 0xe029, 0x3384, 0x0792, 0xf00c, 0x2f10, 0x94f6, 0x9621, 0x30c8, 0x05d1, 0xf011, 0x2f01, 0xcff0, 0x5011, 0xbf11, 0x5f1f, 0x2f01, 0x01ec, 0xc010, 0xdc77, 0x5384, 0x4099, 0xff97, 0xc003, 0x9590, 0x9581, 0x4f9f, 0x178c, 0x079d, 0xf414, 0xb701, 0x01ec, 0xb781, 0x5f8f, 0xbf81, 0xb721, 0xe030, 0x2f81, 0xe090, 0x9601, 0x1782, 0x0793, 0xf744, 0xbf01, 0x91df, 0x91cf, 0x911f, 0x910f, 0x90ff, 0x9508, 0x94f8, 0xcfff, 0xff5a, 0xbc17, 0x0840 +}; + +uint16_t bootloader_address = 6080; diff --git a/upgrade/generate-data.rb b/upgrade/generate-data.rb new file mode 100644 index 0000000..c54f679 --- /dev/null +++ b/upgrade/generate-data.rb @@ -0,0 +1,34 @@ +require_relative "../ruby/micronucleus.rb" + +data = HexProgram.new(open ARGV.first) + +puts data.instance_variable_get(:@bytes).inspect + +data = data.bytes + +# find start address +start_address = 0 +start_address += 1 while data[start_address] == 0xFF + +# trim blank padding data from start of data +start_address.times { data.shift } + +# if data is an odd number of bytes make it even +data.push 0xFF while (data.length % 2) != 0 + +puts "Length: #{data.length}" +puts "Start address: #{start_address}" + +File.open "bootloader_data.c", "w" do |file| + file.puts "// This file contains the bootloader data itself and the address to install the bootloader at" + file.puts "// Use generate-data.rb with ruby 1.9 to generate these values from a hex file" + file.puts "// Generated from #{ARGV.first} at #{Time.now}" + file.puts "" + file.puts "uint16_t bootloader_data[#{data.length / 2}] PROGMEM = {" + file.puts data.each_slice(2).map { |big_end, little_end| + "0x#{ ((little_end * 256) + big_end).to_s(16).rjust(4, '0') }" + }.join(', ') + file.puts "};" + file.puts "" + file.puts "uint16_t bootloader_address = #{start_address};" +end
\ No newline at end of file diff --git a/upgrade/readme.txt b/upgrade/readme.txt new file mode 100644 index 0000000..fceee4b --- /dev/null +++ b/upgrade/readme.txt @@ -0,0 +1,15 @@ +Micronucleus Upgrade +==================== + +Upgrade is a virus-like payload you can upload via micronucleus (or other bootloaders) to install a new version of micronucleus on the target chip. The upgrade program works by copying the contents of a bootloader hex file in to a progmem array, then bricking the device so it doesn't enter the bootloader on reset but instead runs the upgrader program exclusively. Next it erases and rewrites the bootloader in place at the same address the hex file specifies (BOOTLOADER_ADDRESS in the case of micronucleus). Once the bootloader has been rewritten, upgrade rewrites it's own interrupt vector table to point every interrupt including reset straight at the newly uploaded bootloader's interrupt vector table at whichever address it was installed. + +The program then emits a beep if a piezo speaker is connected between PB0 and PB1. If you have no speaker, use an LED with positive on PB0. Premade upgraders are included in releases/ for micronucleus builds. Just upload one in the usual way and wait for the beep. Once you hear the beep, power down the device and turn it back on - it should launch your new bootloader! + + +Creating an Upgrader +==================== + + ruby generate-data my_bootloader.hex + make clean; make + +Next upload the 'upgrade.hex' file generated, via whichever bootloader you're using. If you're using micronucleus and have the command line tool installed: micronucleus --run upgrade.hex diff --git a/upgrade/releases/micronucleus-1.03-upgrade.hex b/upgrade/releases/micronucleus-1.03-upgrade.hex new file mode 100644 index 0000000..7635e4e --- /dev/null +++ b/upgrade/releases/micronucleus-1.03-upgrade.hex @@ -0,0 +1,177 @@ +:1000000016C428C427C426C425C424C423C422C4B7
+:1000100021C420C41FC41EC41DC41CC41BC422C0D0
+:1000200040C06CC03EC03DC03CC03BC03AC039C0BF
+:1000300038C037C036C035C034C033C004030904EB
+:1000400012011001FF000008D01653070301000041
+:1000500000010902120001010080320904000000C1
+:100060000000000011241FBECFE5D2E0DEBFCDBFEF
+:1000700000EB0F9307E00F9310E0A0E6B0E0EAEC8E
+:10008000FFE102C005900D92A636B107D9F710E046
+:10009000A6E6B0E001C01D92AA39B107E1F7DFD1B1
+:1000A000C1C3BDCFA82FB92F80E090E041E050EA56
+:1000B000609530E009C02D9182279795879510F0C3
+:1000C00084279527305EC8F36F5FA8F30895EADFB1
+:1000D0008D939D930895A6E088279927AA9569F0A6
+:1000E0000197E1F3B399FCCFB39BFECF81E0992751
+:1000F000A6B3019611F0A871D9F70895CF93CFB7A1
+:10010000CF93C0915F02C03B21F4C0915E02C73023
+:1001100021F0CF91CFBFCF9181CFCC27C395B39B97
+:10012000E9F7B39B0BC0B39B09C0B39B07C0B39B5C
+:1001300005C0B39B03C0B39B01C0D3C00F92DF9334
+:10014000C0917D00DD27CC57DF4F012EB39B03C04C
+:10015000DF910F90E6CF2F930F931F934F932FEFC5
+:100160004F6F06B303FB20F95F933F9350E03BE0F2
+:1001700065C016B30126502953FDC89556B3012713
+:1001800003FB25F92F7306B3B1F05027102713FB9B
+:1001900026F906B22230F0F000C016B3012703FBA7
+:1001A00027F90126502906B22430E8F54F77206858
+:1001B00016B30000F6CF50274F7D206206B2102FF5
+:1001C000000000C006B300265029102713FB26F9B3
+:1001D00006B2E2CF4F7B06B3206400C0DACF01261F
+:1001E0005029187106B269F14E7F2160012F16B3B4
+:1001F00028C0002650294D7F06B22260102F29C04A
+:10020000012650294B7F06B22460012F2DC016B362
+:1002100001265029477F2860000006B22EC04F7E7D
+:1002200006B3206130C0422706B349930026502907
+:10023000102706B24FEF13FB20F9297F16B379F28E
+:10024000187159F10126502906B2012703FB21F943
+:10025000237F06B371F2002650293150D0F006B248
+:10026000102713FB22F9277E16B351F201265029DD
+:10027000012703FB06B223F92F7C49F2000006B3E5
+:10028000102713FB24F90026502906B22F7939F2E2
+:1002900070CF10E21ABF002717C03B503195C31B27
+:1002A000D04010E21ABF0881033CF9F00B34E9F0AA
+:1002B00020917B001981110F1213EDCF093651F1F6
+:1002C0000D3211F0013E39F7009382003F915F91AA
+:1002D0004F911F910F912F91DF910F90CAB7C5FDDC
+:1002E0001DCFCF91CFBFCF911895209182002223AF
+:1002F00069F310918000112321F5343022F13093FD
+:10030000800020937C0010917D003BE0311B3093F6
+:100310007D0019C00091800001309CF40AE5309105
+:10032000600034FD11C000936000C0E7D0E010C051
+:10033000052710E000C021C0052710E0C89508BBC4
+:1003400014C03AE501C032ED032EC0E0D0E032E047
+:1003500017B31861C39A08B317BB58E120E84FEFF1
+:1003600020FF052708BB279517951C3F28F700009D
+:100370004552B0F720FF0527279508BB17951C3F6E
+:10038000B8F629913A9561F7077E10918100110F17
+:1003900008BBC250D04011F010937B0010E21ABF8E
+:1003A000086017B3177E402F477E54E05A95F1F747
+:1003B00008BB17BB48BB8ACF81E080936700F894E5
+:1003C000E0916E00F0916F00329785E080935700C6
+:1003D000E89507B600FCFDCF789408959C01E09164
+:1003E0006E00F0916F00309749F1E430F105B1F003
+:1003F00087E1EC3BF80739F420916A0030916B00FB
+:100400002E5D3B4F0DC087E1EE3BF80749F420918C
+:100410006C0030916D002D5D3B4F02C02FED3BEC29
+:10042000F89481E0090180935700E89511247894AD
+:100430003296F0936F00E0936E00089581E180930F
+:100440005700E895EBCF8FEF9FEFC8DF80916E00EC
+:1004500090916F008F739070892BA9F7ADCF88E1D1
+:100460000FB6F89481BD11BC0FBEE0E0F0E08591BD
+:1004700094918F5D9B4C39F4E4E0F0E08591949188
+:100480008F5D9B4C09F0DFDF10926F0010926E00C1
+:10049000AC9A8BB780628BBFBB9A88E893E1ECE99A
+:1004A000F1E03197F1F70197D1F7BB987894EE24FA
+:1004B000FF2410918000135017FDD0C080917D0063
+:1004C000CCE0D0E0C81BD109CC57DF4F80917C0035
+:1004D0008D3209F08DC0183009F0BEC083EC8093D6
+:1004E00070008AE580936000109269002881822F55
+:1004F00080769981882309F1992341F482E690E07E
+:1005000090937F0080937E0024E068C0913051F486
+:100510008C819D8190936F0080936E0027FD59C060
+:100520009FEF58C080916600923011F4816001C045
+:1005300084608093660020E051C08A811092790027
+:10054000992331F410927A0089E790E022E03CC0D0
+:10055000953019F48093810034C0963011F58B8169
+:10056000813019F482EE97E104C0823041F484EFC7
+:1005700097E190937F0080937E0022E10EC083304C
+:1005800059F48A81882341F48EED97E190937F009E
+:1005900080937E0024E001C020E080E48093690025
+:1005A0001DC0983019F483E890E009C0993019F41F
+:1005B0008093830006C09A3021F489E790E021E01F
+:1005C00003C089E790E020E090937F0080937E0055
+:1005D00005C09E8180E88093690007C08F818823D1
+:1005E00019F49E81921708F0922F9093610034C005
+:1005F0008091690087FF30C080916E0090916F00FC
+:10060000009739F48881998190936B0080936A00F8
+:100610000DC08430910539F48881998190936D00E3
+:1006200080936C0003C0805C974138F48881998185
+:10063000D5DE125011F02296DFCF80916E0090919E
+:100640006F008F739070892B39F4809166008260FF
+:10065000809366001092610010928000809160008B
+:1006600084FF3CC0809161008F3FC1F1182F893019
+:1006700008F018E0811B809361008091700098E879
+:100680008927809370001123E1F0E0917E00F091C2
+:100690007F008091690086FF09C0912FA1E7B0E03B
+:1006A00084918D9331969150D9F707C0912FA1E78E
+:1006B000B0E081918D939150E1F7F0937F00E0934A
+:1006C0007E0081E790E0612F02DD612F6C5F6C306E
+:1006D00019F08FEF809361006093600094E186B31E
+:1006E000887131F49150D9F71092810010927B00FB
+:1006F00010E0992309F411E080916800811739F026
+:10070000112319F4F8944FD07894109368008CE971
+:1007100091E00197F1F780916600882319F0EE24AB
+:10072000FF2403C00894E11CF11C182F80FF14C0A3
+:10073000F894E0ECF7E1E054F04083E08093570058
+:10074000E89507B600FCFDCF3097A9F710926F002F
+:1007500010926E0078DE789411FF0FC08AE390E269
+:100760000197F1F780916E0090916F008F739070F8
+:10077000892B11F068DE01C01FDE12FD08C0109247
+:10078000660080E5E81683ECF80608F492CE82E273
+:1007900091EA0197F1F7F8941BBE15BA10925F0227
+:1007A00010925E023ACCFF920F931F93CF93DF9388
+:1007B00080E8F82E00E0C0E0D0E0102F1F0D11BF40
+:1007C0008ADC29E0843392070CF0102FF6942196EE
+:1007D000C830D10511F0012FF0CF115011BF1F5FAC
+:1007E000012FEC0110C077DC8453994097FF03C0C0
+:1007F000909581959F4F8C179D0714F401B7EC01DC
+:1008000081B78F5F81BF21B730E0812F90E00196E3
+:100810008217930744F701BFDF91CF911F910F918A
+:10082000FF900895F894FFCF5AFF17BC4008112499
+:100830001FBECFE5D2E0DEBFCDBF10E0A0E6B0E046
+:10084000EEEEFAE002C005900D92A236B107D9F79C
+:100850001BD14BC1D5CB05C0EDE1F0E13197F1F7EC
+:1008600001970097C9F70895AC01407C20E030E083
+:10087000F901E40FF51F85919491F901EE7FE60FE0
+:10088000F71F918380832E5F3F4F2034310581F71E
+:100890000895FC01E07C83E080935700E89507B65B
+:1008A00000FCFDCF0895CF93DF93EC01A0E0B0E012
+:1008B000AD014C0F5D1FFB01EA0FFB1F8081918191
+:1008C00021E0FA010C0120935700E89511241296BB
+:1008D000A034B10569F785E0FE0180935700E895E3
+:1008E00007B600FCFDCFDF91CF910895DF93CF9342
+:1008F000CDB7DEB7C054D0400FB6F894DEBF0FBE00
+:10090000CDBF209160003091610036952795215030
+:100910003044FE01319621933193CE018F5B9F4F7E
+:10092000E817F907C1F780E090E0B3DF80E090E0DE
+:10093000BE016F5F7F4FB7DFC05CDF4F0FB6F8942B
+:10094000DEBF0FBECDBFCF91DF910895EF92FF9232
+:100950000F931F93DF93CF93CDB7DEB7C054D04032
+:100960000FB6F894DEBF0FBECDBF00E010E035C07B
+:100970009B01359527957E010894E11CF11C88E0C8
+:10098000AE32B80738F0220F331FE20EF31E8FEF9E
+:100990009FEF07C0FD0185919491220F331FE20E56
+:1009A000F31EF701918380836E5F7F4F1296603450
+:1009B0007105F1F68091600090916100800F911FA8
+:1009C00068DF8091600090916100800F911FBE01EF
+:1009D0006F5F7F4F68DF005C1F4FF8E000341F0738
+:1009E00031F0D801A25EBF4F60E070E0C1CFC05CC3
+:1009F000DF4F0FB6F894DEBF0FBECDBFCF91DF91B2
+:100A00001F910F91FF90EF900895DF93CF93CDB793
+:100A1000DEB7C054D0400FB6F894DEBF0FBECDBFD6
+:100A200080E090E0BE016F5F7F4F1EDF80E090E0CE
+:100A300001968F309105E1F78FEF9FEF9A838983BD
+:100A400080E090E026DF80E090E0BE016F5F7F4FA6
+:100A50002ADFC05CDF4F0FB6F894DEBF0FBECDBFFC
+:100A6000CF91DF91089587B3836087BB20E08DE14C
+:100A700090E1FC013197F1F7C19A0197F1F7C19824
+:100A80002F5F2A3FA1F7089584E690E0EDE1F0E1C1
+:100A90003197F1F70197D1F7F894B7DF57DF26DFE9
+:100AA000E2DF80E090E00895000000000000000018
+:100AB0000000000000000000000000000000000036
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:0E0AE00000000000000000000895F894FFCF11
+:020AEE00C0172F
+:00000001FF
diff --git a/upgrade/upgrade.c b/upgrade/upgrade.c new file mode 100644 index 0000000..3d54acf --- /dev/null +++ b/upgrade/upgrade.c @@ -0,0 +1,165 @@ +// Upgrade is an in-place firmware upgrader for tiny85 chips - just fill in the +// 'bootloaderAddress' variable in bootloader_data.h, and the bootloaderData +// progmem array with the bootloader data, and you're ready to go. +// +// Upgrade will firstly rewrite the interrupt vector table to disable the bootloader, +// rewriting it to just run the upgrade app. Next it erases and writes each page of the +// bootloader in sequence, erasing over any remaining pages leaving them set to 0xFFFF +// Finally upgrader erases it's interrupt table again and fills it with RJMPs to +// bootloaderAddress, effectively bridging the interrupts in to the new bootloader's +// interrupts table. +// +// While upgrade has been written with attiny85 and micronucleus in mind, it should +// work with other bootloaders and other chips with flash self program but no hardware +// bootloader protection, where the bootloader exists at the end of flash +// +// Be very careful to not power down the AVR while upgrader is running. +// If you connect a piezo between pb0 and pb1 you'll hear a bleep when the update +// is complete. You can also connect an LED with pb0 positive and pb1 or gnd negative and +// it will blink + +#include "./utils.h" +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include <avr/wdt.h> +#include <avr/boot.h> +#include "./bootloader_data.c" + +void secure_interrupt_vector_table(void); +void write_new_bootloader(void); +void forward_interrupt_vector_table(void); +void beep(void); + +void load_table(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]); +void erase_page(uint16_t address); +void write_page(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]); + + +int main(void) { + delay(100); // milliseconds + cli(); + + secure_interrupt_vector_table(); // reset our vector table to it's original state + write_new_bootloader(); + forward_interrupt_vector_table(); + + beep(); + + return 0; +} + +// erase first page, removing any interrupt table hooks the bootloader added when +// upgrade was uploaded +void secure_interrupt_vector_table(void) { + uint16_t table[SPM_PAGESIZE / 2]; + + load_table(0, table); + + // wipe out any interrupt hooks the bootloader rewrote + int i = 0; + while (i < 15) { + table[0] = 0xFFFF; + i++; + } + + erase_page(0); + write_page(0, table); +} + +// erase bootloader's section and write over it with new bootloader code +void write_new_bootloader(void) { + uint16_t outgoing_page[SPM_PAGESIZE / 2]; + int iter = 0; + while (iter < sizeof(bootloader_data)) { + + // read in one page's worth of data from progmem + int word_addr = 0; + while (word_addr < SPM_PAGESIZE) { + int subaddress = ((int) bootloader_data) + iter + word_addr; + if (subaddress >= ((int) bootloader_data) + sizeof(bootloader_data)) { + outgoing_page[word_addr / 2] = 0xFFFF; + } else { + outgoing_page[word_addr / 2] = pgm_read_word(subaddress); + } + + word_addr += 2; + } + + // erase page in destination + erase_page(bootloader_address + iter); + // write updated page + write_page(bootloader_address + iter, outgoing_page); + + iter += 64; + } +} + +// write in forwarding interrupt vector table +void forward_interrupt_vector_table(void) { + uint16_t vector_table[SPM_PAGESIZE / 2]; + + int iter = 0; + while (iter < SPM_PAGESIZE / 2) { + // rjmp to bootloader_address's interrupt table + vector_table[iter] = 0xC000 + (bootloader_address / 2) - 1; + iter++; + } + + erase_page(0); + write_page(0, vector_table); +} + +void load_table(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]) { + uint16_t subaddress = 0; + address -= address % SPM_PAGESIZE; // round down to nearest page start + + while (subaddress < SPM_PAGESIZE) { + words[subaddress / 2] = pgm_read_word(address + subaddress); + subaddress += 2; + } +} + +void erase_page(uint16_t address) { + boot_page_erase(address - (address % SPM_PAGESIZE)); + boot_spm_busy_wait(); +} + +void write_page(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]) { + // fill buffer + uint16_t iter = 0; + while (iter < SPM_PAGESIZE / 2) { + boot_page_fill(address + (iter * 2), words[iter]); + iter++; + } + + boot_page_write(address); + boot_spm_busy_wait(); // Wait until the memory is written. +} + +// beep for a quarter of a second +void beep(void) { + outputs(pin(0) | pin(1)); + + byte i = 0; + while (i < 250) { + delay(1); + pinOn(pin(0)); + delay(1); + pinOff(pin(0)); + i++; + } +} + +////////////// Add padding to start of program so no program code could reasonably be erased while program is running +// this never needs to be called - avr-gcc stuff happening: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html +void PadStartOfProgram (void) __attribute__ ((naked)) __attribute__ ((section (".init0"))); +void PushMagicWord (void) { + // 32 words of nop - a whole page's worth + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); + asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); +} + + diff --git a/upgrade/utils.h b/upgrade/utils.h new file mode 100644 index 0000000..c84ee56 --- /dev/null +++ b/upgrade/utils.h @@ -0,0 +1,90 @@ +#include <util/delay_basic.h> +#include <avr/io.h> + +// For the niceness +typedef unsigned char byte; +typedef unsigned char boolean; + +// make bit & value, eg bit(5) #=> 0b00010000 +#define bit(number) _BV(number) +#define pin(number) _BV(number) + +// USI serial aliases +#define USIOutputPort PORTE +#define USIInputPort PINE +#define USIDirectionPort DDRE +#define USIClockPin PE4 +#define USIDataInPin PE5 +#define USIDataOutPin PE6 + +// booleans +#define on 255 +#define off 0 +#define true 1 +#define false 0 +#define yes true +#define no false + +// ensure a value is within the bounds of a minimum and maximum (inclusive) +#define constrainUpper(value, max) (value > max ? max : value) +#define constrainLower(value, min) (value < min ? min : value) +#define constrain(value, min, max) constrainLower(constrainUpper(value, max), min) +#define multiplyDecimal(a,b) (((a) * (b)) / 256) + +// set a pin on DDRB to be an input or an output - i.e. becomeOutput(pin(3)); +#define inputs(pinmap) DDRB &= ~(pinmap) +#define outputs(pinmap) DDRB |= (pinmap) + +// turn some pins on or off +#define pinsOn(pinmap) PORTB |= (pinmap) +#define pinsOff(pinmap) PORTB &= ~(pinmap) +#define pinsToggle(pinmap) PORTB ^= pinmap + +// turn a single pin on or off +#define pinOn(pin) pinsOn(bit(pin)) +#define pinOff(pin) pinsOff(bit(pin)) +// TODO: Should be called pinToggle +#define toggle(pin) pinsToggle(bit(pin)) + +// delay a number of microseconds - or as close as we can get +#if F_CPU == 16500000 + // special version to deal with half-mhz speed. in a resolution of 2us increments, rounded up + // this loop has been tuned empirically with an oscilloscope and works in avr-gcc 4.5.1 + static inline void microdelay(int microseconds) { + while (microseconds > 1) { + // 16 nops + asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); + asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); + // 16 nops + asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP");asm("NOP"); + asm("NOP");asm("NOP");asm("NOP"); + + + microseconds -= 2; + } + } +#else + #define microdelay(microseconds) _delay_loop_2(((microseconds) * (F_CPU / 100000)) / 40) +#endif + +// delay in milliseconds - a custom implementation to avoid util/delay's tendancy to import floating point math libraries +inline void delay(unsigned int ms) { + while (ms > 0) { + // delay for one millisecond (250*4 cycles, multiplied by cpu mhz) + // subtract number of time taken in while loop and decrement and other bits + _delay_loop_2((25 * F_CPU / 100000)); + ms--; + } +} + + + +// digital read returns 0 or 1 +#define get(pin) ((PINB >> pin) & 0b00000001) +#define getBitmap(bitmap) (PINB & bitmap) +static inline void set(byte pin, byte state) { + if (state) { pinOn(pin); } else { pinOff(pin); } + // alternatly: + // PORTB = (PORTB & ~(bit(pin)) | ((state & 1) << pin); +} + |