From fcb989e284991b78f7e118e275f42af62e6a3d8e Mon Sep 17 00:00:00 2001 From: gmattinson <46222855+gmattinson@users.noreply.github.com> Date: Fri, 28 Dec 2018 20:18:16 -0500 Subject: [PATCH 1/3] Added optiboot_copy method. --- optiboot/bootloaders/optiboot/optiboot.c | 26 +++++- .../optiboot/optiboot_atmega328.hex | 88 ++++++++++++------- 2 files changed, 81 insertions(+), 33 deletions(-) diff --git a/optiboot/bootloaders/optiboot/optiboot.c b/optiboot/bootloaders/optiboot/optiboot.c index ab59436af..a88ae98c5 100644 --- a/optiboot/bootloaders/optiboot/optiboot.c +++ b/optiboot/bootloaders/optiboot/optiboot.c @@ -165,6 +165,9 @@ /**********************************************************/ /* Edit History: */ /* */ +/* Jan 2019 */ +/* 8.1 gmattinson: Create do_spm_copy at BOOTSTART+4 to */ +/* make self-updating code easier */ /* Sep 2018 */ /* 8.0 WestfW (and Majekw and MCUDude) */ /* Include do_spm routine callable from the app */ @@ -252,7 +255,7 @@ /**********************************************************/ #define OPTIBOOT_MAJVER 8 -#define OPTIBOOT_MINVER 0 +#define OPTIBOOT_MINVER 1 /* * OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits @@ -510,6 +513,11 @@ void pre_main(void) { #else " ret\n" // if do_spm isn't include, return without doing anything #endif +#ifdef BIGBOOT + " rjmp do_spm_copy\n" +#else + " ret\n" // if do_spm_copy isn't included, return without doing anything +#endif "1:\n" ); } @@ -1357,4 +1365,20 @@ OPT2FLASH(OPTIBOOT_CUSTOMVER); #endif char f_version[] = "Version=" xstr(OPTIBOOT_MAJVER) "." xstr(OPTIBOOT_MINVER); +void do_spm_copy(uint16_t dst, uint16_t src, uint8_t numPages, void(*retFunc)(void)) __attribute__((used)); +void do_spm_copy(uint16_t dst, uint16_t src, uint8_t numPages, void(*retFunc)(void)) { + uint8_t i, j; + + if (numPages == 0) return; + + for (i = 0; i < numPages; i++) { + do_spm(dst + i * SPM_PAGESIZE, __BOOT_PAGE_ERASE, 0); + for (j = 0; j < SPM_PAGESIZE; j += 2) { + do_spm(dst + i * SPM_PAGESIZE + j, __BOOT_PAGE_FILL, pgm_read_word(src + i * SPM_PAGESIZE + j)); + } + do_spm(dst + i * SPM_PAGESIZE, __BOOT_PAGE_WRITE, 0); + } + retFunc(); +} + #endif diff --git a/optiboot/bootloaders/optiboot/optiboot_atmega328.hex b/optiboot/bootloaders/optiboot/optiboot_atmega328.hex index 482b3e8b2..cc31d0e48 100644 --- a/optiboot/bootloaders/optiboot/optiboot_atmega328.hex +++ b/optiboot/bootloaders/optiboot/optiboot_atmega328.hex @@ -1,33 +1,57 @@ -:107E000001C0DCC0112484B7882361F0982F9A70D8 -:107E1000923041F081FF02C097EF94BF282E80E09E -:107E2000B8D0EEC085E08093810082E08093C000EE -:107E300088E18093C10086E08093C20080E1809356 -:107E4000C4008EE0A6D0259A86E020E33CEF91E0C6 -:107E5000309385002093840096BBB09BFECF1D9A83 -:107E6000A8954091C00047FD02C0815089F7EE24DB -:107E7000E39495E0D92E21E1C22E7FD0813461F4C4 -:107E80007CD0182F8CD01238E9F0113811F488E02A -:107E900001C083E06BD067C0823411F484E103C079 -:107EA000853419F485E083D05EC0853539F465D01A -:107EB000C82F63D0D82FCC0FDD1F54C0863521F4D6 -:107EC00084E075D080E0E6CF843609F02EC055D02E -:107ED00054D0F82E52D0B82E00E011E04ED0F80168 -:107EE00081938F01FE12FACF5AD0F5E4BF1201C080 -:107EF000FFCF83E0FE0187BFE89507B600FCFDCF0A -:107F0000A0E0B1E0FE018D919D910C01E7BEE895E6 -:107F100011243296FA12F7CFFE01D7BEE89507B6C4 -:107F200000FCFDCFC7BEE8951EC0843771F425D094 -:107F300024D0F82E22D033D08E01F80185918F0104 -:107F400015D0FA94F110F9CF0EC0853739F427D047 -:107F50008EE10CD085E90AD08FE09CCF813511F4F9 -:107F600088E017D01CD080E101D087CF9091C0006D -:107F700095FFFCCF8093C60008958091C00087FFD5 -:107F8000FCCF8091C00084FD01C0A8958091C600FF -:107F90000895E0E6F0E098E1908380830895EDDFB6 -:107FA000803219F088E0F5DFFFCF84E1DFCFCF9397 -:107FB000C82FE3DFC150E9F7CF91F1CFFC010A01EF -:107FC00067BFE895112407B600FCFDCF667029F065 -:0C7FD000452B19F481E187BFE895089566 -:027FFE00000879 -:0400000300007E007B +:107C000002C0E3C0F2C0112484B7882361F0982F2A +:107C10009A70923041F081FF02C097EF94BF282EF6 +:107C200080E0BED0EDC182E08093C00088E1809307 +:107C3000C10086E08093C20080E18093C4008EE0A2 +:107C4000AFD093E0D92ECC24C39425E0B22E31E1FD +:107C5000A32E9AD0813471F497D0182FA7D0123860 +:107C600011F481E005C0113811F488E001C083E00F +:107C700084D080C0823411F484E103C0853419F4C7 +:107C800085E09CD077C0853539F47ED0C82F7CD074 +:107C9000D82FCC0FDD1F6DC0863521F484E08ED047 +:107CA00080E0E6CF843609F03BC06ED06DD0982ED0 +:107CB0006BD0F82E00E011E067D0F80181938F01BE +:107CC0009E12FACF73D0F5E4FF120FC07E0100E0E0 +:107CD00011E0901609F44EC0F80161918F01C701BF +:107CE000DDD0FFEFEF1AFF0AF4CFFE01D7BEE89513 +:107CF00007B600FCFDCFFE01A0E0B1E08D919D91A3 +:107D00000C01C7BEE895112432969A12F7CFFE01F6 +:107D1000B7BEE89507B600FCFDCFA7BEE8952AC020 +:107D20008437D1F431D030D0F82E2ED0E82E3ED08A +:107D30008E01F5E4EF1209C0FC0EC801A7D01DD0DA +:107D40000F5F1F4FF012F9CF15C0F80185918F0119 +:107D500014D0FA94D1F70EC0853739F427D08EE1CC +:107D60000CD085E90AD08FE083CF813511F488E00B +:107D700017D01CD080E101D06CCF9091C00095FF4E +:107D8000FCCF8093C60008958091C00087FFFCCF90 +:107D90008091C00084FD01C0A8958091C60008951F +:107DA000E0E6F0E098E1908380830895EDDF803293 +:107DB00019F088E0F5DFFFCF84E1DFCFCF93C82F44 +:107DC000E3DFC150E9F7CF91F1CFFC010A0167BFB2 +:107DD000E895112407B600FCFDCF667029F0452B0D +:107DE00019F481E187BFE89508959F92AF92BF9201 +:107DF000CF92DF92EF92FF920F931F93CF93DF9377 +:107E0000B42E79014423B1F1EC01A12C6B01C81A05 +:107E1000D90A40E050E063E0CE01D7DF8E01912C1B +:107E2000F601E00FF11F4591549161E0C801CDDFEB +:107E3000939493940E5F1F4F80E89812F1CF40E027 +:107E400050E065E0CE01C1DFA394C058DF4FAB1016 +:107E5000E0CF8FEF98E09EBF8DBFF701DF91CF910C +:107E60001F910F91FF90EF90DF90CF90BF90AF9058 +:107E70009F900994DF91CF911F910F91FF90EF9008 +:107E8000DF90CF90BF90AF909F900895F999FECF6B +:107E900092BD81BDF89A992780B50895262FF9994A +:107EA000FECF1FBA92BD81BD20BD0FB6F894FA9ADD +:087EB000F99A0FBE0196089536 +:107EB80056657273696F6E3D382E31004F505449C4 +:107EC800424F4F545F435553544F4D5645523D30E2 +:107ED800004465766963653D61746D656761333239 +:107EE800387000465F4350553D31363030303030C1 +:107EF800304C00424947424F4F543D31004275696A +:107F08006C743A44656320323820323031383A3064 +:107F1800373A30323A343600554152543D300042F7 +:107F28004155445F524154453D313135323030007E +:107F38004C45443D4235004C45445F5354415254EE +:0C7F48005F464C41534845533D3000005B +:027FFE00010878 +:0400000300007C007D :00000001FF From f331f6596018b46169a090f03fb1bb7ed5998155 Mon Sep 17 00:00:00 2001 From: gmattinson <46222855+gmattinson@users.noreply.github.com> Date: Fri, 28 Dec 2018 20:23:31 -0500 Subject: [PATCH 2/3] Created example for optiboot_copy --- optiboot/examples/program_blink/optiboot.h | 182 +++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 optiboot/examples/program_blink/optiboot.h diff --git a/optiboot/examples/program_blink/optiboot.h b/optiboot/examples/program_blink/optiboot.h new file mode 100644 index 000000000..2111633f6 --- /dev/null +++ b/optiboot/examples/program_blink/optiboot.h @@ -0,0 +1,182 @@ +/*------------------------ Optiboot header file ----------------------------| + | | + | June 2015 by Marek Wodzinski, https://github.com/majekw | + | Modified June 2016 by MCUdude, https://github.com/MCUdude | + | Released to public domain | + | | + | This header file gives possibility to use SPM instruction | + | from Optiboot bootloader memory. | + | | + | There are 6 convenient functions available here: | + | * optiboot_page_erase - to erase a FLASH page | + | * optiboot_page_fill - to put words into temporary buffer | + | * optiboot_page_write - to write contents of temporary buffer into FLASH | + | * optiboot_readPage - higher level function to read a flash page and | + | store it in an array | + | * optiboot_writePage - higher level function to write content to | + | a flash page | + | * optiboot_copy - copy FLASH memory from one location to another, and | + | then call to a new address. Useful for flashing new | + | firmware on to your board. | + | | + | For some hardcore users, you could use 'do_spm' as raw entry to | + | bootloader spm function. | + |-------------------------------------------------------------------------*/ + + +#ifndef _OPTIBOOT_H_ +#define _OPTIBOOT_H_ 1 + +#include +#include "Arduino.h" + + +/* + * Main 'magic' function - enter to bootloader do_spm function + * + * address - address to write (in bytes) but must be even number + * command - one of __BOOT_PAGE_WRITE, __BOOT_PAGE_ERASE or __BOOT_PAGE_FILL + * data - data to write in __BOOT_PAGE_FILL. In __BOOT_PAGE_ERASE or + * __BOOT_PAGE_WRITE it control if boot_rww_enable is run + * (0 = run, !0 = skip running boot_rww_enable) + * + */ + +// 'typedef' (in following line) and 'const' (few lines below) are a way to define external function at some arbitrary address +typedef void (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data); +typedef void(*retFunc_t)(void); +typedef void(*do_spm_copy_t)(uint16_t dst, uint16_t src, uint8_t numPages, retFunc_t retFunc); + + +/* + * Devices with more than 64KB of flash: + * - have larger bootloader area (1KB) (they are BIGBOOT targets) + * - have RAMPZ register :-) + * - need larger variable to hold address (pgmspace.h uses uint32_t) + */ +#ifdef RAMPZ + typedef uint32_t optiboot_addr_t; +#else + typedef uint16_t optiboot_addr_t; +#endif + +#if (FLASHEND > 65534) || defined(BIGBOOT) + const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1); + const do_spm_copy_t do_spm_copy = (do_spm_copy_t)((FLASHEND - 1023 + 4) >> 1); +#else + const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1); +#endif + + +/* + * The same as do_spm but with disable/restore interrupts state + * required to succesfull SPM execution + * + * On devices with more than 64kB flash, 16 bit address is not enough, + * so there is also RAMPZ used in that case. + */ +void do_spm_cli(optiboot_addr_t address, uint8_t command, uint16_t data) { + uint8_t sreg_save; + + sreg_save = SREG; // save old SREG value + asm volatile("cli"); // disable interrupts + #ifdef RAMPZ + RAMPZ = (address >> 16) & 0xff; // address bits 23-16 goes to RAMPZ + do_spm((address & 0xffff), command, data); // do_spm accepts only lower 16 bits of address + #else + do_spm(address, command, data); // 16 bit address - no problems to pass directly + #endif + SREG = sreg_save; // restore last interrupts state +} + + +// Erase page in FLASH +void optiboot_page_erase(optiboot_addr_t address) { + do_spm_cli(address, __BOOT_PAGE_ERASE, 0); +} + + +// Write word into temporary buffer +void optiboot_page_fill(optiboot_addr_t address, uint16_t data) { + do_spm_cli(address, __BOOT_PAGE_FILL, data); +} + + +//Write temporary buffer into FLASH +void optiboot_page_write(optiboot_addr_t address) { + do_spm_cli(address, __BOOT_PAGE_WRITE, 0); +} + + + +/* + * Higher level functions for reading and writing from flash + * See the examples for more info on how to use these functions + */ + +// Function to read a flash page and store it in an array (storage_array[]) +void optiboot_readPage(const uint8_t allocated_flash_space[], uint8_t storage_array[], uint16_t page, char blank_character) +{ + uint8_t read_character; + for(uint16_t j = 0; j < SPM_PAGESIZE; j++) + { + read_character = pgm_read_byte(&allocated_flash_space[j + SPM_PAGESIZE*(page-1)]); + if(read_character != 0 && read_character != 255) + storage_array[j] = read_character; + else + storage_array[j] = blank_character; + } +} + + +// Function to read a flash page and store it in an array (storage_array[]), but without blank_character +void optiboot_readPage(const uint8_t allocated_flash_space[], uint8_t storage_array[], uint16_t page) +{ + uint8_t read_character; + for(uint16_t j = 0; j < SPM_PAGESIZE; j++) + { + read_character = pgm_read_byte(&allocated_flash_space[j + SPM_PAGESIZE*(page-1)]); + if(read_character != 0 && read_character != 255) + storage_array[j] = read_character; + } +} + + +// Function to write data to a flash page +void optiboot_writePage(const uint8_t allocated_flash_space[], uint8_t data_to_store[], uint16_t page) +{ + uint16_t word_buffer = 0; + + // Erase the flash page + optiboot_page_erase((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]); + + // Copy ram buffer to temporary flash buffer + for(uint16_t i = 0; i < SPM_PAGESIZE; i++) + { + if(i % 2 == 0) // We must write words + word_buffer = data_to_store[i]; + else + { + word_buffer += (data_to_store[i] << 8); + optiboot_page_fill((optiboot_addr_t)(void*) &allocated_flash_space[i + SPM_PAGESIZE*(page-1)], word_buffer); + } + } + + // Writing temporary buffer to flash + optiboot_page_write((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]); +} + + +#ifdef BIGBOOT +// Copy from one part of FLASH to another +void optiboot_copy(optiboot_addr_t dst, optiboot_addr_t src, uint8_t numPages, retFunc_t retFunc) { + uint8_t sreg_save; + + sreg_save = SREG; // save old SREG value + asm volatile("cli"); // disable interrupts + do_spm_copy(dst, src, numPages, retFunc); + SREG = sreg_save; // restore last interrupts state +} +#endif + +#endif /* _OPTIBOOT_H_ */ From fe0c9f6460d34002d7d6f9c8444d996d3e47bd69 Mon Sep 17 00:00:00 2001 From: gmattinson <46222855+gmattinson@users.noreply.github.com> Date: Fri, 28 Dec 2018 20:24:04 -0500 Subject: [PATCH 3/3] Created example for optiboot_copy --- .../examples/program_blink/program_blink.ino | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 optiboot/examples/program_blink/program_blink.ino diff --git a/optiboot/examples/program_blink/program_blink.ino b/optiboot/examples/program_blink/program_blink.ino new file mode 100644 index 000000000..0a725928c --- /dev/null +++ b/optiboot/examples/program_blink/program_blink.ino @@ -0,0 +1,103 @@ +/* + * Blink pin 13 four times / second until pin 2 goes low. + * Then flash new firmware which blinks one time / second. + */ + +#define BIGBOOT +#include "optiboot.h" + +/* The following was generated from Blink.ino.hex using cat and sed. There are numerous other options: + * cat Blink.ino.hex | + * sed "s#:..0.....\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(.*\)..#0x\1, 0x\2, 0x\3, 0x\4, 0x\5, 0x\6, 0x\7, 0x\8, \9#" | + * sed "s#, \(.[0-9A-F]\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)#, 0x\1, 0x\2, 0x\3, 0x\4, 0x\5, 0x\6, 0x\7, 0x\8,#" + * It is only 0x406 bytes, but size must be a multiple of SPM_PAGESIZE. + */ +const uint8_t blink1s[0x480] __attribute__((aligned(SPM_PAGESIZE))) PROGMEM= { +0x0C, 0x94, 0x5C, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x88, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, +0x0C, 0x94, 0x6E, 0x00, 0x0C, 0x94, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x01, 0x00, +0x00, 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, +0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, +0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, +0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x2B, 0x00, 0x00, 0x00, +0x00, 0x00, 0x24, 0x00, 0x27, 0x00, 0x2A, 0x00, 0x11, 0x24, 0x1F, 0xBE, 0xCF, 0xEF, 0xD8, 0xE0, +0xDE, 0xBF, 0xCD, 0xBF, 0x21, 0xE0, 0xA0, 0xE0, 0xB1, 0xE0, 0x01, 0xC0, 0x1D, 0x92, 0xA9, 0x30, +0xB2, 0x07, 0xE1, 0xF7, 0x0E, 0x94, 0xF1, 0x01, 0x0C, 0x94, 0x01, 0x02, 0x0C, 0x94, 0x00, 0x00, +0x61, 0xE0, 0x8D, 0xE0, 0x0C, 0x94, 0x81, 0x01, 0x61, 0xE0, 0x8D, 0xE0, 0x0E, 0x94, 0xBA, 0x01, +0x68, 0xEE, 0x73, 0xE0, 0x80, 0xE0, 0x90, 0xE0, 0x0E, 0x94, 0xF5, 0x00, 0x60, 0xE0, 0x8D, 0xE0, +0x0E, 0x94, 0xBA, 0x01, 0x68, 0xEE, 0x73, 0xE0, 0x80, 0xE0, 0x90, 0xE0, 0x0C, 0x94, 0xF5, 0x00, +0x1F, 0x92, 0x0F, 0x92, 0x0F, 0xB6, 0x0F, 0x92, 0x11, 0x24, 0x2F, 0x93, 0x3F, 0x93, 0x8F, 0x93, +0x9F, 0x93, 0xAF, 0x93, 0xBF, 0x93, 0x80, 0x91, 0x01, 0x01, 0x90, 0x91, 0x02, 0x01, 0xA0, 0x91, +0x03, 0x01, 0xB0, 0x91, 0x04, 0x01, 0x30, 0x91, 0x00, 0x01, 0x23, 0xE0, 0x23, 0x0F, 0x2D, 0x37, +0x20, 0xF4, 0x01, 0x96, 0xA1, 0x1D, 0xB1, 0x1D, 0x05, 0xC0, 0x26, 0xE8, 0x23, 0x0F, 0x02, 0x96, +0xA1, 0x1D, 0xB1, 0x1D, 0x20, 0x93, 0x00, 0x01, 0x80, 0x93, 0x01, 0x01, 0x90, 0x93, 0x02, 0x01, +0xA0, 0x93, 0x03, 0x01, 0xB0, 0x93, 0x04, 0x01, 0x80, 0x91, 0x05, 0x01, 0x90, 0x91, 0x06, 0x01, +0xA0, 0x91, 0x07, 0x01, 0xB0, 0x91, 0x08, 0x01, 0x01, 0x96, 0xA1, 0x1D, 0xB1, 0x1D, 0x80, 0x93, +0x05, 0x01, 0x90, 0x93, 0x06, 0x01, 0xA0, 0x93, 0x07, 0x01, 0xB0, 0x93, 0x08, 0x01, 0xBF, 0x91, +0xAF, 0x91, 0x9F, 0x91, 0x8F, 0x91, 0x3F, 0x91, 0x2F, 0x91, 0x0F, 0x90, 0x0F, 0xBE, 0x0F, 0x90, +0x1F, 0x90, 0x18, 0x95, 0x3F, 0xB7, 0xF8, 0x94, 0x80, 0x91, 0x05, 0x01, 0x90, 0x91, 0x06, 0x01, +0xA0, 0x91, 0x07, 0x01, 0xB0, 0x91, 0x08, 0x01, 0x26, 0xB5, 0xA8, 0x9B, 0x05, 0xC0, 0x2F, 0x3F, +0x19, 0xF0, 0x01, 0x96, 0xA1, 0x1D, 0xB1, 0x1D, 0x3F, 0xBF, 0x66, 0x27, 0x78, 0x2F, 0x89, 0x2F, +0x9A, 0x2F, 0x62, 0x0F, 0x71, 0x1D, 0x81, 0x1D, 0x91, 0x1D, 0x42, 0xE0, 0x66, 0x0F, 0x77, 0x1F, +0x88, 0x1F, 0x99, 0x1F, 0x4A, 0x95, 0xD1, 0xF7, 0x08, 0x95, 0xCF, 0x92, 0xDF, 0x92, 0xEF, 0x92, +0xFF, 0x92, 0xCF, 0x93, 0xDF, 0x93, 0x6B, 0x01, 0x7C, 0x01, 0x0E, 0x94, 0xD2, 0x00, 0xEB, 0x01, +0xC1, 0x14, 0xD1, 0x04, 0xE1, 0x04, 0xF1, 0x04, 0x89, 0xF0, 0x0E, 0x94, 0x00, 0x02, 0x0E, 0x94, +0xD2, 0x00, 0x6C, 0x1B, 0x7D, 0x0B, 0x68, 0x3E, 0x73, 0x40, 0x90, 0xF3, 0x81, 0xE0, 0xC8, 0x1A, +0xD1, 0x08, 0xE1, 0x08, 0xF1, 0x08, 0xC8, 0x51, 0xDC, 0x4F, 0xEA, 0xCF, 0xDF, 0x91, 0xCF, 0x91, +0xFF, 0x90, 0xEF, 0x90, 0xDF, 0x90, 0xCF, 0x90, 0x08, 0x95, 0x78, 0x94, 0x84, 0xB5, 0x82, 0x60, +0x84, 0xBD, 0x84, 0xB5, 0x81, 0x60, 0x84, 0xBD, 0x85, 0xB5, 0x82, 0x60, 0x85, 0xBD, 0x85, 0xB5, +0x81, 0x60, 0x85, 0xBD, 0xEE, 0xE6, 0xF0, 0xE0, 0x80, 0x81, 0x81, 0x60, 0x80, 0x83, 0xE1, 0xE8, +0xF0, 0xE0, 0x10, 0x82, 0x80, 0x81, 0x82, 0x60, 0x80, 0x83, 0x80, 0x81, 0x81, 0x60, 0x80, 0x83, +0xE0, 0xE8, 0xF0, 0xE0, 0x80, 0x81, 0x81, 0x60, 0x80, 0x83, 0xE1, 0xEB, 0xF0, 0xE0, 0x80, 0x81, +0x84, 0x60, 0x80, 0x83, 0xE0, 0xEB, 0xF0, 0xE0, 0x80, 0x81, 0x81, 0x60, 0x80, 0x83, 0xEA, 0xE7, +0xF0, 0xE0, 0x80, 0x81, 0x84, 0x60, 0x80, 0x83, 0x80, 0x81, 0x82, 0x60, 0x80, 0x83, 0x80, 0x81, +0x81, 0x60, 0x80, 0x83, 0x80, 0x81, 0x80, 0x68, 0x80, 0x83, 0x10, 0x92, 0xC1, 0x00, 0x08, 0x95, +0x83, 0x30, 0x81, 0xF0, 0x28, 0xF4, 0x81, 0x30, 0x99, 0xF0, 0x82, 0x30, 0xA1, 0xF0, 0x08, 0x95, +0x87, 0x30, 0xA9, 0xF0, 0x88, 0x30, 0xB9, 0xF0, 0x84, 0x30, 0xD1, 0xF4, 0x80, 0x91, 0x80, 0x00, +0x8F, 0x7D, 0x03, 0xC0, 0x80, 0x91, 0x80, 0x00, 0x8F, 0x77, 0x80, 0x93, 0x80, 0x00, 0x08, 0x95, +0x84, 0xB5, 0x8F, 0x77, 0x02, 0xC0, 0x84, 0xB5, 0x8F, 0x7D, 0x84, 0xBD, 0x08, 0x95, 0x80, 0x91, +0xB0, 0x00, 0x8F, 0x77, 0x03, 0xC0, 0x80, 0x91, 0xB0, 0x00, 0x8F, 0x7D, 0x80, 0x93, 0xB0, 0x00, +0x08, 0x95, 0xCF, 0x93, 0xDF, 0x93, 0x90, 0xE0, 0xFC, 0x01, 0xE4, 0x58, 0xFF, 0x4F, 0x24, 0x91, +0xFC, 0x01, 0xE0, 0x57, 0xFF, 0x4F, 0x84, 0x91, 0x88, 0x23, 0x49, 0xF1, 0x90, 0xE0, 0x88, 0x0F, +0x99, 0x1F, 0xFC, 0x01, 0xE2, 0x55, 0xFF, 0x4F, 0xA5, 0x91, 0xB4, 0x91, 0x8C, 0x55, 0x9F, 0x4F, +0xFC, 0x01, 0xC5, 0x91, 0xD4, 0x91, 0x9F, 0xB7, 0x61, 0x11, 0x08, 0xC0, 0xF8, 0x94, 0x8C, 0x91, +0x20, 0x95, 0x82, 0x23, 0x8C, 0x93, 0x88, 0x81, 0x82, 0x23, 0x0A, 0xC0, 0x62, 0x30, 0x51, 0xF4, +0xF8, 0x94, 0x8C, 0x91, 0x32, 0x2F, 0x30, 0x95, 0x83, 0x23, 0x8C, 0x93, 0x88, 0x81, 0x82, 0x2B, +0x88, 0x83, 0x04, 0xC0, 0xF8, 0x94, 0x8C, 0x91, 0x82, 0x2B, 0x8C, 0x93, 0x9F, 0xBF, 0xDF, 0x91, +0xCF, 0x91, 0x08, 0x95, 0x0F, 0x93, 0x1F, 0x93, 0xCF, 0x93, 0xDF, 0x93, 0x1F, 0x92, 0xCD, 0xB7, +0xDE, 0xB7, 0x28, 0x2F, 0x30, 0xE0, 0xF9, 0x01, 0xE8, 0x59, 0xFF, 0x4F, 0x84, 0x91, 0xF9, 0x01, +0xE4, 0x58, 0xFF, 0x4F, 0x14, 0x91, 0xF9, 0x01, 0xE0, 0x57, 0xFF, 0x4F, 0x04, 0x91, 0x00, 0x23, +0xC9, 0xF0, 0x88, 0x23, 0x21, 0xF0, 0x69, 0x83, 0x0E, 0x94, 0x58, 0x01, 0x69, 0x81, 0xE0, 0x2F, +0xF0, 0xE0, 0xEE, 0x0F, 0xFF, 0x1F, 0xEC, 0x55, 0xFF, 0x4F, 0xA5, 0x91, 0xB4, 0x91, 0x9F, 0xB7, +0xF8, 0x94, 0x8C, 0x91, 0x61, 0x11, 0x03, 0xC0, 0x10, 0x95, 0x81, 0x23, 0x01, 0xC0, 0x81, 0x2B, +0x8C, 0x93, 0x9F, 0xBF, 0x0F, 0x90, 0xDF, 0x91, 0xCF, 0x91, 0x1F, 0x91, 0x0F, 0x91, 0x08, 0x95, +0x08, 0x95, 0x0E, 0x94, 0x1D, 0x01, 0x0E, 0x94, 0xF0, 0x01, 0x0E, 0x94, 0x70, 0x00, 0xC0, 0xE0, +0xD0, 0xE0, 0x0E, 0x94, 0x74, 0x00, 0x20, 0x97, 0xE1, 0xF3, 0x0E, 0x94, 0x00, 0x00, 0xF9, 0xCF, +0x08, 0x95, 0xF8, 0x94, 0xFF, 0xCF }; + + +// the setup function runs once when you press reset or power the board +void setup() { + // initialize digital pin 13 as an output. + pinMode(13, OUTPUT); + // initialize digital pin 2 as input with a pull up resistor to simplify the circuit. + pinMode(2, INPUT_PULLUP); +} + +// the loop function runs over and over again forever +void loop() { + digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) + delay(250); // wait for 250 ms + digitalWrite(13, LOW); // turn the LED off by making the voltage LOW + delay(250); // wait for 250 ms + if (digitalRead(2) == 0) { + // Copy blink1s (the program we want to run now) + // to address 0 (the address programs normally run at) + // then jump to address 0 (ie. reset the device) + optiboot_copy(0, (uint16_t)blink1s, sizeof(blink1s) / SPM_PAGESIZE, 0); + } +}