--- /dev/null
+/**********************************************************/\r
+/* Serial Bootloader for Atmel megaAVR Controllers */\r
+/* */\r
+/* tested with ATmega8, ATmega128 and ATmega168 */\r
+/* should work with other mega's, see code for details */\r
+/* */\r
+/* ATmegaBOOT.c */\r
+/* */\r
+/* */\r
+/* 20090308: integrated Mega changes into main bootloader */\r
+/* source by D. Mellis */\r
+/* 20080930: hacked for Arduino Mega (with the 1280 */\r
+/* processor, backwards compatible) */\r
+/* by D. Cuartielles */\r
+/* 20070626: hacked for Arduino Diecimila (which auto- */\r
+/* resets when a USB connection is made to it) */\r
+/* by D. Mellis */\r
+/* 20060802: hacked for Arduino by D. Cuartielles */\r
+/* based on a previous hack by D. Mellis */\r
+/* and D. Cuartielles */\r
+/* */\r
+/* Monitor and debug functions were added to the original */\r
+/* code by Dr. Erik Lins, chip45.com. (See below) */\r
+/* */\r
+/* Thanks to Karl Pitrich for fixing a bootloader pin */\r
+/* problem and more informative LED blinking! */\r
+/* */\r
+/* For the latest version see: */\r
+/* http://www.chip45.com/ */\r
+/* */\r
+/* ------------------------------------------------------ */\r
+/* */\r
+/* based on stk500boot.c */\r
+/* Copyright (c) 2003, Jason P. Kyle */\r
+/* All rights reserved. */\r
+/* see avr1.org for original file and information */\r
+/* */\r
+/* This program is free software; you can redistribute it */\r
+/* and/or modify it under the terms of the GNU General */\r
+/* Public License as published by the Free Software */\r
+/* Foundation; either version 2 of the License, or */\r
+/* (at your option) any later version. */\r
+/* */\r
+/* This program is distributed in the hope that it will */\r
+/* be useful, but WITHOUT ANY WARRANTY; without even the */\r
+/* implied warranty of MERCHANTABILITY or FITNESS FOR A */\r
+/* PARTICULAR PURPOSE. See the GNU General Public */\r
+/* License for more details. */\r
+/* */\r
+/* You should have received a copy of the GNU General */\r
+/* Public License along with this program; if not, write */\r
+/* to the Free Software Foundation, Inc., */\r
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */\r
+/* */\r
+/* Licence can be viewed at */\r
+/* http://www.fsf.org/licenses/gpl.txt */\r
+/* */\r
+/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */\r
+/* m8515,m8535. ATmega161 has a very small boot block so */\r
+/* isn't supported. */\r
+/* */\r
+/* Tested with m168 */\r
+/**********************************************************/\r
+\r
+\r
+/* some includes */\r
+#include <inttypes.h>\r
+#include <avr/io.h>\r
+#include <avr/pgmspace.h>\r
+#include <avr/interrupt.h>\r
+#include <avr/wdt.h>\r
+#include <util/delay.h>\r
+\r
+/* the current avr-libc eeprom functions do not support the ATmega168 */\r
+/* own eeprom write/read functions are used instead */\r
+#if !defined(__AVR_ATmega168__) || !defined(__AVR_ATmega328P__) || !defined(__AVR_ATmega328__) || defined(__AVR_ATmega644P__)\r
+#include <avr/eeprom.h>\r
+#endif\r
+\r
+/* Use the F_CPU defined in Makefile */\r
+\r
+/* 20060803: hacked by DojoCorp */\r
+/* 20070626: hacked by David A. Mellis to decrease waiting time for auto-reset */\r
+/* set the waiting time for the bootloader */\r
+/* get this from the Makefile instead */\r
+/* #define MAX_TIME_COUNT (F_CPU>>4) */\r
+\r
+/* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */\r
+#define MAX_ERROR_COUNT 5\r
+\r
+/* set the UART baud rate */\r
+/* 20060803: hacked by DojoCorp */\r
+//#define BAUD_RATE 115200\r
+#ifndef BAUD_RATE\r
+#define BAUD_RATE 19200\r
+#endif\r
+\r
+\r
+/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */\r
+/* never allow AVR Studio to do an update !!!! */\r
+#define HW_VER 0x02\r
+#define SW_MAJOR 0x01\r
+#define SW_MINOR 0x10\r
+\r
+\r
+/* Adjust to suit whatever pin your hardware uses to enter the bootloader */\r
+/* ATmega128 has two UARTS so two pins are used to enter bootloader and select UART */\r
+/* ATmega1280 has four UARTS, but for Arduino Mega, we will only use RXD0 to get code */\r
+/* BL0... means UART0, BL1... means UART1 */\r
+#ifdef __AVR_ATmega128__\r
+#define BL_DDR DDRF\r
+#define BL_PORT PORTF\r
+#define BL_PIN PINF\r
+#define BL0 PINF7\r
+#define BL1 PINF6\r
+#elif defined __AVR_ATmega1280__ \r
+/* we just don't do anything for the MEGA and enter bootloader on reset anyway*/\r
+#else\r
+/* other ATmegas have only one UART, so only one pin is defined to enter bootloader */\r
+#define BL_DDR DDRD\r
+#define BL_PORT PORTD\r
+#define BL_PIN PIND\r
+#define BL PIND6\r
+#endif\r
+\r
+\r
+/* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */\r
+/* if monitor functions are included, LED goes on after monitor was entered */\r
+#if defined __AVR_ATmega128__ || defined __AVR_ATmega1280__\r
+/* Onboard LED is connected to pin PB7 (e.g. Crumb128, PROBOmega128, Savvy128, Arduino Mega) */\r
+#define LED_DDR DDRB\r
+#define LED_PORT PORTB\r
+#define LED_PIN PINB\r
+#define LED PINB7\r
+#elif __AVR_ATmega644P__\r
+#define LED_DDR DDRC\r
+#define LED_PORT PORTC\r
+#define LED_PIN PINC\r
+#define LED PINC4\r
+\r
+#else\r
+/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duomilanuove */ \r
+/* other boards like e.g. Crumb8, Crumb168 are using PB2 */\r
+#define LED_DDR DDRB\r
+#define LED_PORT PORTB\r
+#define LED_PIN PINB\r
+#define LED PINB5\r
+#endif\r
+\r
+\r
+/* monitor functions will only be compiled when using ATmega128, due to bootblock size constraints */\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+#define MONITOR 1\r
+#endif\r
+\r
+\r
+/* define various device id's */\r
+/* manufacturer byte is always the same */\r
+#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(\r
+\r
+#if defined __AVR_ATmega1280__\r
+#define SIG2 0x97\r
+#define SIG3 0x03\r
+#define PAGE_SIZE 0x80U //128 words\r
+\r
+#elif defined __AVR_ATmega1281__\r
+#define SIG2 0x97\r
+#define SIG3 0x04\r
+#define PAGE_SIZE 0x80U //128 words\r
+\r
+#elif defined __AVR_ATmega128__\r
+#define SIG2 0x97\r
+#define SIG3 0x02\r
+#define PAGE_SIZE 0x80U //128 words\r
+\r
+#elif defined __AVR_ATmega64__\r
+#define SIG2 0x96\r
+#define SIG3 0x02\r
+#define PAGE_SIZE 0x80U //128 words\r
+\r
+#elif defined __AVR_ATmega32__\r
+#define SIG2 0x95\r
+#define SIG3 0x02\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega16__\r
+#define SIG2 0x94\r
+#define SIG3 0x03\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega8__\r
+#define SIG2 0x93\r
+#define SIG3 0x07\r
+#define PAGE_SIZE 0x20U //32 words\r
+\r
+#elif defined __AVR_ATmega88__\r
+#define SIG2 0x93\r
+#define SIG3 0x0a\r
+#define PAGE_SIZE 0x20U //32 words\r
+\r
+#elif defined __AVR_ATmega168__\r
+#define SIG2 0x94\r
+#define SIG3 0x06\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega328P__\r
+#define SIG2 0x95\r
+#define SIG3 0x0F\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega328__\r
+#define SIG2 0x95\r
+#define SIG3 0x14\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega644P__\r
+#define SIG2 0x96\r
+#define SIG3 0x0A\r
+#define PAGE_SIZE 0x80U //128 words\r
+\r
+#elif defined __AVR_ATmega162__\r
+#define SIG2 0x94\r
+#define SIG3 0x04\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega163__\r
+#define SIG2 0x94\r
+#define SIG3 0x02\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega169__\r
+#define SIG2 0x94\r
+#define SIG3 0x05\r
+#define PAGE_SIZE 0x40U //64 words\r
+\r
+#elif defined __AVR_ATmega8515__\r
+#define SIG2 0x93\r
+#define SIG3 0x06\r
+#define PAGE_SIZE 0x20U //32 words\r
+\r
+#elif defined __AVR_ATmega8535__\r
+#define SIG2 0x93\r
+#define SIG3 0x08\r
+#define PAGE_SIZE 0x20U //32 words\r
+#endif\r
+\r
+\r
+/* function prototypes */\r
+void putch(char);\r
+char getch(void);\r
+void getNch(uint8_t);\r
+void byte_response(uint8_t);\r
+void nothing_response(void);\r
+char gethex(void);\r
+void puthex(char);\r
+void flash_led(uint8_t);\r
+\r
+/* some variables */\r
+union address_union {\r
+ uint16_t word;\r
+ uint8_t byte[2];\r
+} address;\r
+\r
+union length_union {\r
+ uint16_t word;\r
+ uint8_t byte[2];\r
+} length;\r
+\r
+struct flags_struct {\r
+ unsigned eeprom : 1;\r
+ unsigned rampz : 1;\r
+} flags;\r
+\r
+uint8_t buff[256];\r
+uint8_t address_high;\r
+\r
+uint8_t pagesz=0x80;\r
+\r
+uint8_t i;\r
+uint8_t bootuart = 0;\r
+\r
+uint8_t error_count = 0;\r
+\r
+void (*app_start)(void) = 0x0000;\r
+\r
+\r
+/* main program starts here */\r
+int main(void)\r
+{\r
+ uint8_t ch,ch2;\r
+ uint16_t w;\r
+\r
+\r
+#ifdef __AVR_ATmega644P__\r
+ DDRC = 0x1C;\r
+ PORTC = 0;\r
+#endif\r
+\r
+#ifdef WATCHDOG_MODS\r
+ ch = MCUSR;\r
+ MCUSR = 0;\r
+\r
+ WDTCSR |= _BV(WDCE) | _BV(WDE);\r
+ WDTCSR = 0;\r
+\r
+ // Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.\r
+ if (! (ch & _BV(EXTRF))) // if its a not an external reset...\r
+ app_start(); // skip bootloader\r
+#else\r
+ asm volatile("nop\n\t");\r
+#endif\r
+\r
+ /* set pin direction for bootloader pin and enable pullup */\r
+ /* for ATmega128, two pins need to be initialized */\r
+#ifdef __AVR_ATmega128__\r
+ BL_DDR &= ~_BV(BL0);\r
+ BL_DDR &= ~_BV(BL1);\r
+ BL_PORT |= _BV(BL0);\r
+ BL_PORT |= _BV(BL1);\r
+#else\r
+ /* We run the bootloader regardless of the state of this pin. Thus, don't\r
+ put it in a different state than the other pins. --DAM, 070709\r
+ This also applies to Arduino Mega -- DC, 080930\r
+ BL_DDR &= ~_BV(BL);\r
+ BL_PORT |= _BV(BL);\r
+ */\r
+#endif\r
+\r
+\r
+#ifdef __AVR_ATmega128__\r
+ /* check which UART should be used for booting */\r
+ if(bit_is_clear(BL_PIN, BL0)) {\r
+ bootuart = 1;\r
+ }\r
+ else if(bit_is_clear(BL_PIN, BL1)) {\r
+ bootuart = 2;\r
+ }\r
+#endif\r
+\r
+#if defined __AVR_ATmega1280__\r
+ /* the mega1280 chip has four serial ports ... we could eventually use any of them, or not? */\r
+ /* however, we don't wanna confuse people, to avoid making a mess, we will stick to RXD0, TXD0 */\r
+ bootuart = 1;\r
+#endif\r
+\r
+ /* check if flash is programmed already, if not start bootloader anyway */\r
+ if(pgm_read_byte_near(0x0000) != 0xFF) {\r
+\r
+#ifdef __AVR_ATmega128__\r
+ /* no UART was selected, start application */\r
+ if(!bootuart) {\r
+ app_start();\r
+ }\r
+#else\r
+ /* check if bootloader pin is set low */\r
+ /* we don't start this part neither for the m8, nor m168 */\r
+ //if(bit_is_set(BL_PIN, BL)) {\r
+ // app_start();\r
+ // }\r
+#endif\r
+ }\r
+\r
+#ifdef __AVR_ATmega128__ \r
+ /* no bootuart was selected, default to uart 0 */\r
+ if(!bootuart) {\r
+ bootuart = 1;\r
+ }\r
+#endif\r
+\r
+\r
+ /* initialize UART(s) depending on CPU defined */\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ if(bootuart == 1) {\r
+ UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);\r
+ UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;\r
+ UCSR0A = 0x00;\r
+ UCSR0C = 0x06;\r
+ UCSR0B = _BV(TXEN0)|_BV(RXEN0);\r
+ }\r
+ if(bootuart == 2) {\r
+ UBRR1L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);\r
+ UBRR1H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;\r
+ UCSR1A = 0x00;\r
+ UCSR1C = 0x06;\r
+ UCSR1B = _BV(TXEN1)|_BV(RXEN1);\r
+ }\r
+#elif defined __AVR_ATmega163__\r
+ UBRR = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);\r
+ UBRRHI = (F_CPU/(BAUD_RATE*16L)-1) >> 8;\r
+ UCSRA = 0x00;\r
+ UCSRB = _BV(TXEN)|_BV(RXEN); \r
+#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined __AVR_ATmega644P__\r
+\r
+#ifdef DOUBLE_SPEED\r
+ UCSR0A = (1<<U2X0); //Double speed mode USART0\r
+ UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*8L)-1);\r
+ UBRR0H = (F_CPU/(BAUD_RATE*8L)-1) >> 8;\r
+#else\r
+ UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);\r
+ UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;\r
+#endif\r
+\r
+ UCSR0B = (1<<RXEN0) | (1<<TXEN0);\r
+ UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);\r
+\r
+ /* Enable internal pull-up resistor on pin D0 (RX), in order\r
+ to suppress line noise that prevents the bootloader from\r
+ timing out (DAM: 20070509) */\r
+ DDRD &= ~_BV(PIND0);\r
+ PORTD |= _BV(PIND0);\r
+#elif defined __AVR_ATmega8__\r
+ /* m8 */\r
+ UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate\r
+ UBRRL = (((F_CPU/BAUD_RATE)/16)-1);\r
+ UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx\r
+ UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1\r
+#else\r
+ /* m16,m32,m169,m8515,m8535 */\r
+ UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);\r
+ UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8;\r
+ UCSRA = 0x00;\r
+ UCSRC = 0x06;\r
+ UCSRB = _BV(TXEN)|_BV(RXEN);\r
+#endif\r
+\r
+#if defined __AVR_ATmega1280__\r
+ /* Enable internal pull-up resistor on pin D0 (RX), in order\r
+ to suppress line noise that prevents the bootloader from\r
+ timing out (DAM: 20070509) */\r
+ /* feature added to the Arduino Mega --DC: 080930 */\r
+ DDRE &= ~_BV(PINE0);\r
+ PORTE |= _BV(PINE0);\r
+#endif\r
+\r
+\r
+ /* set LED pin as output */\r
+ LED_DDR |= _BV(LED);\r
+\r
+\r
+ /* flash onboard LED to signal entering of bootloader */\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ // 4x for UART0, 5x for UART1\r
+ flash_led(NUM_LED_FLASHES + bootuart);\r
+#else\r
+ flash_led(NUM_LED_FLASHES);\r
+#endif\r
+\r
+ /* 20050803: by DojoCorp, this is one of the parts provoking the\r
+ system to stop listening, cancelled from the original */\r
+ //putch('\0');\r
+\r
+ /* forever loop */\r
+ for (;;) {\r
+\r
+ /* get character from UART */\r
+ ch = getch();\r
+\r
+ /* A bunch of if...else if... gives smaller code than switch...case ! */\r
+\r
+ /* Hello is anyone home ? */ \r
+ if(ch=='0') {\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* Request programmer ID */\r
+ /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundary */\r
+ /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */\r
+ else if(ch=='1') {\r
+ if (getch() == ' ') {\r
+ putch(0x14);\r
+ putch('A');\r
+ putch('V');\r
+ putch('R');\r
+ putch(' ');\r
+ putch('I');\r
+ putch('S');\r
+ putch('P');\r
+ putch(0x10);\r
+ } else {\r
+ if (++error_count == MAX_ERROR_COUNT)\r
+ app_start();\r
+ }\r
+ }\r
+\r
+\r
+ /* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */\r
+ else if(ch=='@') {\r
+ ch2 = getch();\r
+ if (ch2>0x85) getch();\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* AVR ISP/STK500 board requests */\r
+ else if(ch=='A') {\r
+ ch2 = getch();\r
+ if(ch2==0x80) byte_response(HW_VER); // Hardware version\r
+ else if(ch2==0x81) byte_response(SW_MAJOR); // Software major version\r
+ else if(ch2==0x82) byte_response(SW_MINOR); // Software minor version\r
+ else if(ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56\r
+ else byte_response(0x00); // Covers various unnecessary responses we don't care about\r
+ }\r
+\r
+\r
+ /* Device Parameters DON'T CARE, DEVICE IS FIXED */\r
+ else if(ch=='B') {\r
+ getNch(20);\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* Parallel programming stuff DON'T CARE */\r
+ else if(ch=='E') {\r
+ getNch(5);\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* P: Enter programming mode */\r
+ /* R: Erase device, don't care as we will erase one page at a time anyway. */\r
+ else if(ch=='P' || ch=='R') {\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* Leave programming mode */\r
+ else if(ch=='Q') {\r
+ nothing_response();\r
+#ifdef WATCHDOG_MODS\r
+ // autoreset via watchdog (sneaky!)\r
+ WDTCSR = _BV(WDE);\r
+ while (1); // 16 ms\r
+#endif\r
+ }\r
+\r
+\r
+ /* Set address, little endian. EEPROM in bytes, FLASH in words */\r
+ /* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */\r
+ /* This might explain why little endian was used here, big endian used everywhere else. */\r
+ else if(ch=='U') {\r
+ address.byte[0] = getch();\r
+ address.byte[1] = getch();\r
+ nothing_response();\r
+ }\r
+\r
+\r
+ /* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */\r
+ else if(ch=='V') {\r
+ if (getch() == 0x30) {\r
+ getch();\r
+ ch = getch();\r
+ getch();\r
+ if (ch == 0) {\r
+ byte_response(SIG1);\r
+ } else if (ch == 1) {\r
+ byte_response(SIG2); \r
+ } else {\r
+ byte_response(SIG3);\r
+ } \r
+ } else {\r
+ getNch(3);\r
+ byte_response(0x00);\r
+ }\r
+ }\r
+\r
+\r
+ /* Write memory, length is big endian and is in bytes */\r
+ else if(ch=='d') {\r
+ length.byte[1] = getch();\r
+ length.byte[0] = getch();\r
+ flags.eeprom = 0;\r
+ if (getch() == 'E') flags.eeprom = 1;\r
+ for (w=0;w<length.word;w++) {\r
+ buff[w] = getch(); // Store data in buffer, can't keep up with serial data stream whilst programming pages\r
+ }\r
+ if (getch() == ' ') {\r
+ if (flags.eeprom) { //Write to EEPROM one byte at a time\r
+ address.word <<= 1;\r
+ for(w=0;w<length.word;w++) {\r
+#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega644P__)\r
+ while(EECR & (1<<EEPE));\r
+ EEAR = (uint16_t)(void *)address.word;\r
+ EEDR = buff[w];\r
+ EECR |= (1<<EEMPE);\r
+ EECR |= (1<<EEPE);\r
+#else\r
+ eeprom_write_byte((void *)address.word,buff[w]);\r
+#endif\r
+ address.word++;\r
+ } \r
+ }\r
+ else { //Write to FLASH one page at a time\r
+ if (address.byte[1]>127) address_high = 0x01; //Only possible with m128, m256 will need 3rd address byte. FIXME\r
+ else address_high = 0x00;\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__)\r
+ RAMPZ = address_high;\r
+#endif\r
+ address.word = address.word << 1; //address * 2 -> byte location\r
+ /* if ((length.byte[0] & 0x01) == 0x01) length.word++; //Even up an odd number of bytes */\r
+ if ((length.byte[0] & 0x01)) length.word++; //Even up an odd number of bytes\r
+ cli(); //Disable interrupts, just to be sure\r
+#if defined(EEPE)\r
+ while(bit_is_set(EECR,EEPE)); //Wait for previous EEPROM writes to complete\r
+#else\r
+ while(bit_is_set(EECR,EEWE)); //Wait for previous EEPROM writes to complete\r
+#endif\r
+ asm volatile(\r
+ "clr r17 \n\t" //page_word_count\r
+ "lds r30,address \n\t" //Address of FLASH location (in bytes)\r
+ "lds r31,address+1 \n\t"\r
+ "ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM\r
+ "ldi r29,hi8(buff) \n\t"\r
+ "lds r24,length \n\t" //Length of data to be written (in bytes)\r
+ "lds r25,length+1 \n\t"\r
+ "length_loop: \n\t" //Main loop, repeat for number of words in block \r
+ "cpi r17,0x00 \n\t" //If page_word_count=0 then erase page\r
+ "brne no_page_erase \n\t" \r
+ "wait_spm1: \n\t"\r
+ "lds r16,%0 \n\t" //Wait for previous spm to complete\r
+ "andi r16,1 \n\t"\r
+ "cpi r16,1 \n\t"\r
+ "breq wait_spm1 \n\t"\r
+ "ldi r16,0x03 \n\t" //Erase page pointed to by Z\r
+ "sts %0,r16 \n\t"\r
+ "spm \n\t" \r
+#ifdef __AVR_ATmega163__\r
+ ".word 0xFFFF \n\t"\r
+ "nop \n\t"\r
+#endif\r
+ "wait_spm2: \n\t"\r
+ "lds r16,%0 \n\t" //Wait for previous spm to complete\r
+ "andi r16,1 \n\t"\r
+ "cpi r16,1 \n\t"\r
+ "breq wait_spm2 \n\t" \r
+\r
+ "ldi r16,0x11 \n\t" //Re-enable RWW section\r
+ "sts %0,r16 \n\t" \r
+ "spm \n\t"\r
+#ifdef __AVR_ATmega163__\r
+ ".word 0xFFFF \n\t"\r
+ "nop \n\t"\r
+#endif\r
+ "no_page_erase: \n\t" \r
+ "ld r0,Y+ \n\t" //Write 2 bytes into page buffer\r
+ "ld r1,Y+ \n\t" \r
+ \r
+ "wait_spm3: \n\t"\r
+ "lds r16,%0 \n\t" //Wait for previous spm to complete\r
+ "andi r16,1 \n\t"\r
+ "cpi r16,1 \n\t"\r
+ "breq wait_spm3 \n\t"\r
+ "ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer\r
+ "sts %0,r16 \n\t"\r
+ "spm \n\t"\r
+ \r
+ "inc r17 \n\t" //page_word_count++\r
+ "cpi r17,%1 \n\t"\r
+ "brlo same_page \n\t" //Still same page in FLASH\r
+ "write_page: \n\t"\r
+ "clr r17 \n\t" //New page, write current one first\r
+ "wait_spm4: \n\t"\r
+ "lds r16,%0 \n\t" //Wait for previous spm to complete\r
+ "andi r16,1 \n\t"\r
+ "cpi r16,1 \n\t"\r
+ "breq wait_spm4 \n\t"\r
+#ifdef __AVR_ATmega163__\r
+ "andi r30,0x80 \n\t" // m163 requires Z6:Z1 to be zero during page write\r
+#endif \r
+ "ldi r16,0x05 \n\t" //Write page pointed to by Z\r
+ "sts %0,r16 \n\t"\r
+ "spm \n\t"\r
+#ifdef __AVR_ATmega163__\r
+ ".word 0xFFFF \n\t"\r
+ "nop \n\t"\r
+ "ori r30,0x7E \n\t" // recover Z6:Z1 state after page write (had to be zero during write)\r
+#endif\r
+ "wait_spm5: \n\t"\r
+ "lds r16,%0 \n\t" //Wait for previous spm to complete\r
+ "andi r16,1 \n\t"\r
+ "cpi r16,1 \n\t"\r
+ "breq wait_spm5 \n\t" \r
+ "ldi r16,0x11 \n\t" //Re-enable RWW section\r
+ "sts %0,r16 \n\t" \r
+ "spm \n\t" \r
+#ifdef __AVR_ATmega163__\r
+ ".word 0xFFFF \n\t"\r
+ "nop \n\t"\r
+#endif\r
+ "same_page: \n\t" \r
+ "adiw r30,2 \n\t" //Next word in FLASH\r
+ "sbiw r24,2 \n\t" //length-2\r
+ "breq final_write \n\t" //Finished\r
+ "rjmp length_loop \n\t"\r
+ "final_write: \n\t"\r
+ "cpi r17,0 \n\t"\r
+ "breq block_done \n\t"\r
+ "adiw r24,2 \n\t" //length+2, fool above check on length after short page write\r
+ "rjmp write_page \n\t"\r
+ "block_done: \n\t"\r
+ "clr __zero_reg__ \n\t" //restore zero register\r
+#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega644P__)\r
+ : "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"\r
+\r
+#else\r
+ : "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"\r
+#endif\r
+ );\r
+ /* Should really add a wait for RWW section to be enabled, don't actually need it since we never */\r
+ /* exit the bootloader without a power cycle anyhow */\r
+ }\r
+ putch(0x14);\r
+ putch(0x10);\r
+ } else {\r
+ if (++error_count == MAX_ERROR_COUNT)\r
+ app_start();\r
+ } \r
+ }\r
+\r
+\r
+ /* Read memory block mode, length is big endian. */\r
+ else if(ch=='t') {\r
+ length.byte[1] = getch();\r
+ length.byte[0] = getch();\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ if (address.word>0x7FFF) flags.rampz = 1; // No go with m256, FIXME\r
+ else flags.rampz = 0;\r
+#endif\r
+ address.word = address.word << 1; // address * 2 -> byte location\r
+ if (getch() == 'E') flags.eeprom = 1;\r
+ else flags.eeprom = 0;\r
+ if (getch() == ' ') { // Command terminator\r
+ putch(0x14);\r
+ for (w=0;w < length.word;w++) { // Can handle odd and even lengths okay\r
+ if (flags.eeprom) { // Byte access EEPROM read\r
+#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega644P__)\r
+ while(EECR & (1<<EEPE));\r
+ EEAR = (uint16_t)(void *)address.word;\r
+ EECR |= (1<<EERE);\r
+ putch(EEDR);\r
+#else\r
+ putch(eeprom_read_byte((void *)address.word));\r
+#endif\r
+ address.word++;\r
+ }\r
+ else {\r
+\r
+ if (!flags.rampz) putch(pgm_read_byte_near(address.word));\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ else putch(pgm_read_byte_far(address.word + 0x10000));\r
+ // Hmmmm, yuck FIXME when m256 arrives\r
+#endif\r
+ address.word++;\r
+ }\r
+ }\r
+ putch(0x10);\r
+ }\r
+ }\r
+\r
+\r
+ /* Get device signature bytes */\r
+ else if(ch=='u') {\r
+ if (getch() == ' ') {\r
+ putch(0x14);\r
+ putch(SIG1);\r
+ putch(SIG2);\r
+ putch(SIG3);\r
+ putch(0x10);\r
+ } else {\r
+ if (++error_count == MAX_ERROR_COUNT)\r
+ app_start();\r
+ }\r
+ }\r
+\r
+\r
+ /* Read oscillator calibration byte */\r
+ else if(ch=='v') {\r
+ byte_response(0x00);\r
+ }\r
+\r
+\r
+#if defined MONITOR \r
+\r
+ /* here come the extended monitor commands by Erik Lins */\r
+\r
+ /* check for three times exclamation mark pressed */\r
+ else if(ch=='!') {\r
+ ch = getch();\r
+ if(ch=='!') {\r
+ ch = getch();\r
+ if(ch=='!') {\r
+ PGM_P welcome = "";\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ uint16_t extaddr;\r
+#endif\r
+ uint8_t addrl, addrh;\r
+\r
+#ifdef CRUMB128\r
+ welcome = "ATmegaBOOT / Crumb128 - (C) J.P.Kyle, E.Lins - 050815\n\r";\r
+#elif defined PROBOMEGA128\r
+ welcome = "ATmegaBOOT / PROBOmega128 - (C) J.P.Kyle, E.Lins - 050815\n\r";\r
+#elif defined SAVVY128\r
+ welcome = "ATmegaBOOT / Savvy128 - (C) J.P.Kyle, E.Lins - 050815\n\r";\r
+#elif defined __AVR_ATmega1280__ \r
+ welcome = "ATmegaBOOT / Arduino Mega - (C) Arduino LLC - 090930\n\r";\r
+#endif\r
+\r
+ /* turn on LED */\r
+ LED_DDR |= _BV(LED);\r
+ LED_PORT &= ~_BV(LED);\r
+\r
+ /* print a welcome message and command overview */\r
+ for(i=0; welcome[i] != '\0'; ++i) {\r
+ putch(welcome[i]);\r
+ }\r
+\r
+ /* test for valid commands */\r
+ for(;;) {\r
+ putch('\n');\r
+ putch('\r');\r
+ putch(':');\r
+ putch(' ');\r
+\r
+ ch = getch();\r
+ putch(ch);\r
+\r
+ /* toggle LED */\r
+ if(ch == 't') {\r
+ if(bit_is_set(LED_PIN,LED)) {\r
+ LED_PORT &= ~_BV(LED);\r
+ putch('1');\r
+ } else {\r
+ LED_PORT |= _BV(LED);\r
+ putch('0');\r
+ }\r
+ } \r
+\r
+ /* read byte from address */\r
+ else if(ch == 'r') {\r
+ ch = getch(); putch(ch);\r
+ addrh = gethex();\r
+ addrl = gethex();\r
+ putch('=');\r
+ ch = *(uint8_t *)((addrh << 8) + addrl);\r
+ puthex(ch);\r
+ }\r
+\r
+ /* write a byte to address */\r
+ else if(ch == 'w') {\r
+ ch = getch(); putch(ch);\r
+ addrh = gethex();\r
+ addrl = gethex();\r
+ ch = getch(); putch(ch);\r
+ ch = gethex();\r
+ *(uint8_t *)((addrh << 8) + addrl) = ch;\r
+ }\r
+\r
+ /* read from uart and echo back */\r
+ else if(ch == 'u') {\r
+ for(;;) {\r
+ putch(getch());\r
+ }\r
+ }\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ /* external bus loop */\r
+ else if(ch == 'b') {\r
+ putch('b');\r
+ putch('u');\r
+ putch('s');\r
+ MCUCR = 0x80;\r
+ XMCRA = 0;\r
+ XMCRB = 0;\r
+ extaddr = 0x1100;\r
+ for(;;) {\r
+ ch = *(volatile uint8_t *)extaddr;\r
+ if(++extaddr == 0) {\r
+ extaddr = 0x1100;\r
+ }\r
+ }\r
+ }\r
+#endif\r
+\r
+ else if(ch == 'j') {\r
+ app_start();\r
+ }\r
+\r
+ } /* end of monitor functions */\r
+\r
+ }\r
+ }\r
+ }\r
+ /* end of monitor */\r
+#endif\r
+ else if (++error_count == MAX_ERROR_COUNT) {\r
+ app_start();\r
+ }\r
+ } /* end of forever loop */\r
+\r
+}\r
+\r
+\r
+char gethexnib(void) {\r
+ char a;\r
+ a = getch(); putch(a);\r
+ if(a >= 'a') {\r
+ return (a - 'a' + 0x0a);\r
+ } else if(a >= '0') {\r
+ return(a - '0');\r
+ }\r
+ return a;\r
+}\r
+\r
+\r
+char gethex(void) {\r
+ return (gethexnib() << 4) + gethexnib();\r
+}\r
+\r
+\r
+void puthex(char ch) {\r
+ char ah;\r
+\r
+ ah = ch >> 4;\r
+ if(ah >= 0x0a) {\r
+ ah = ah - 0x0a + 'a';\r
+ } else {\r
+ ah += '0';\r
+ }\r
+ \r
+ ch &= 0x0f;\r
+ if(ch >= 0x0a) {\r
+ ch = ch - 0x0a + 'a';\r
+ } else {\r
+ ch += '0';\r
+ }\r
+ \r
+ putch(ah);\r
+ putch(ch);\r
+}\r
+\r
+\r
+void putch(char ch)\r
+{\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ if(bootuart == 1) {\r
+ while (!(UCSR0A & _BV(UDRE0)));\r
+ UDR0 = ch;\r
+ }\r
+ else if (bootuart == 2) {\r
+ while (!(UCSR1A & _BV(UDRE1)));\r
+ UDR1 = ch;\r
+ }\r
+#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined(__AVR_ATmega644P__)\r
+ while (!(UCSR0A & _BV(UDRE0)));\r
+ UDR0 = ch;\r
+#else\r
+ /* m8,16,32,169,8515,8535,163 */\r
+ while (!(UCSRA & _BV(UDRE)));\r
+ UDR = ch;\r
+#endif\r
+}\r
+\r
+\r
+char getch(void)\r
+{\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ uint32_t count = 0;\r
+ if(bootuart == 1) {\r
+ while(!(UCSR0A & _BV(RXC0))) {\r
+ /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ \r
+ /* HACKME:: here is a good place to count times*/\r
+ count++;\r
+ if (count > MAX_TIME_COUNT)\r
+ app_start();\r
+ }\r
+\r
+ return UDR0;\r
+ }\r
+ else if(bootuart == 2) {\r
+ while(!(UCSR1A & _BV(RXC1))) {\r
+ /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ \r
+ /* HACKME:: here is a good place to count times*/\r
+ count++;\r
+ if (count > MAX_TIME_COUNT)\r
+ app_start();\r
+ }\r
+\r
+ return UDR1;\r
+ }\r
+ return 0;\r
+#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega644P__)\r
+ uint32_t count = 0;\r
+ while(!(UCSR0A & _BV(RXC0))){\r
+ /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ \r
+ /* HACKME:: here is a good place to count times*/\r
+ count++;\r
+ if (count > MAX_TIME_COUNT) {\r
+ app_start();\r
+ }\r
+ }\r
+ return UDR0;\r
+\r
+#else\r
+ /* m8,16,32,169,8515,8535,163 */\r
+ uint32_t count = 0;\r
+ while(!(UCSRA & _BV(RXC))){\r
+ /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ \r
+ /* HACKME:: here is a good place to count times*/\r
+ count++;\r
+ if (count > MAX_TIME_COUNT)\r
+ app_start();\r
+ }\r
+ return UDR;\r
+#endif\r
+}\r
+\r
+\r
+void getNch(uint8_t count)\r
+{\r
+ while(count--) {\r
+#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)\r
+ if(bootuart == 1) {\r
+ while(!(UCSR0A & _BV(RXC0)));\r
+ UDR0;\r
+ } \r
+ else if(bootuart == 2) {\r
+ while(!(UCSR1A & _BV(RXC1)));\r
+ UDR1;\r
+ }\r
+#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined(__AVR_ATmega644P__)\r
+ getch();\r
+#else\r
+ /* m8,16,32,169,8515,8535,163 */\r
+ /* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/ \r
+ //while(!(UCSRA & _BV(RXC)));\r
+ //UDR;\r
+ getch(); // need to handle time out\r
+#endif \r
+ }\r
+}\r
+\r
+\r
+void byte_response(uint8_t val)\r
+{\r
+ if (getch() == ' ') {\r
+ putch(0x14);\r
+ putch(val);\r
+ putch(0x10);\r
+ } else {\r
+ if (++error_count == MAX_ERROR_COUNT)\r
+ app_start();\r
+ }\r
+}\r
+\r
+\r
+void nothing_response(void)\r
+{\r
+ if (getch() == ' ') {\r
+ putch(0x14);\r
+ putch(0x10);\r
+ } else {\r
+ if (++error_count == MAX_ERROR_COUNT)\r
+ app_start();\r
+ }\r
+}\r
+\r
+void flash_led(uint8_t count)\r
+{\r
+ while (count--) {\r
+ LED_PORT |= _BV(LED);\r
+ _delay_ms(100);\r
+ LED_PORT &= ~_BV(LED);\r
+ _delay_ms(100);\r
+ }\r
+}\r
+\r
+\r
+/* end of file ATmegaBOOT.c */\r
--- /dev/null
+# Makefile for ATmegaBOOT
+# E.Lins, 18.7.2005
+#
+# 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 = ATmegaBOOT_168
+
+# enter the parameters for the avrdude isp tool
+ISPTOOL = stk500v2
+ISPPORT = usb
+ISPSPEED = -b 115200
+
+MCU_TARGET = atmega168
+LDSECTION = --section-start=.text=0x3800
+
+# 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 0x0f (to
+# lock it), but since the high two bits of the lock byte are
+# unused, avrdude would get confused.
+
+ISPFUSES = avrdude -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 = avrdude -c $(ISPTOOL) -p $(MCU_TARGET) -P $(ISPPORT) $(ISPSPEED) \
+-U flash:w:$(PROGRAM)_$(TARGET).hex -U lock:w:0x0f: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
+
+DEFS =
+LIBS =
+
+CC = 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 = -Wl,$(LDSECTION)
+#override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
+
+OBJCOPY = avr-objcopy
+OBJDUMP = avr-objdump
+
+all:
+
+lilypad: TARGET = lilypad
+lilypad: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>1' '-DNUM_LED_FLASHES=3'
+lilypad: AVR_FREQ = 8000000L
+lilypad: $(PROGRAM)_lilypad.hex
+
+lilypad_isp: lilypad
+lilypad_isp: TARGET = lilypad
+lilypad_isp: HFUSE = DD
+lilypad_isp: LFUSE = E2
+lilypad_isp: EFUSE = 00
+lilypad_isp: isp
+
+lilypad_resonator: TARGET = lilypad_resonator
+lilypad_resonator: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=3'
+lilypad_resonator: AVR_FREQ = 8000000L
+lilypad_resonator: $(PROGRAM)_lilypad_resonator.hex
+
+lilypad_resonator_isp: lilypad_resonator
+lilypad_resonator_isp: TARGET = lilypad_resonator
+lilypad_resonator_isp: HFUSE = DD
+lilypad_resonator_isp: LFUSE = C6
+lilypad_resonator_isp: EFUSE = 00
+lilypad_resonator_isp: isp
+
+pro8: TARGET = pro_8MHz
+pro8: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' '-DWATCHDOG_MODS'
+pro8: AVR_FREQ = 8000000L
+pro8: $(PROGRAM)_pro_8MHz.hex
+
+pro8_isp: pro8
+pro8_isp: TARGET = pro_8MHz
+pro8_isp: HFUSE = DD
+pro8_isp: LFUSE = C6
+pro8_isp: EFUSE = 00
+pro8_isp: isp
+
+pro16: TARGET = pro_16MHz
+pro16: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' '-DWATCHDOG_MODS'
+pro16: AVR_FREQ = 16000000L
+pro16: $(PROGRAM)_pro_16MHz.hex
+
+pro16_isp: pro16
+pro16_isp: TARGET = pro_16MHz
+pro16_isp: HFUSE = DD
+pro16_isp: LFUSE = C6
+pro16_isp: EFUSE = 00
+pro16_isp: isp
+
+pro20: TARGET = pro_20mhz
+pro20: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' '-DWATCHDOG_MODS'
+pro20: AVR_FREQ = 20000000L
+pro20: $(PROGRAM)_pro_20mhz.hex
+
+pro20_isp: pro20
+pro20_isp: TARGET = pro_20mhz
+pro20_isp: HFUSE = DD
+pro20_isp: LFUSE = C6
+pro20_isp: EFUSE = 00
+pro20_isp: isp
+
+diecimila: TARGET = diecimila
+diecimila: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1'
+diecimila: AVR_FREQ = 16000000L
+diecimila: $(PROGRAM)_diecimila.hex
+
+diecimila_isp: diecimila
+diecimila_isp: TARGET = diecimila
+diecimila_isp: HFUSE = DD
+diecimila_isp: LFUSE = FF
+diecimila_isp: EFUSE = 00
+diecimila_isp: isp
+
+ng: TARGET = ng
+ng: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>1' '-DNUM_LED_FLASHES=3'
+ng: AVR_FREQ = 16000000L
+ng: $(PROGRAM)_ng.hex
+
+ng_isp: ng
+ng_isp: TARGET = ng
+ng_isp: HFUSE = DD
+ng_isp: LFUSE = FF
+ng_isp: EFUSE = 00
+ng_isp: isp
+
+atmega644: TARGET = atmega644
+atmega644: MCU_TARGET = atmega644p
+atmega644: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DDOUBLE_SPEED -DBAUD_RATE=115200
+atmega644: AVR_FREQ = 12000000L
+atmega644: LDSECTION = --section-start=.text=0x7000
+atmega644: $(PROGRAM)_atmega644p.hex
+
+atmega644_isp: atmega644
+atmega644_isp: TARGET = atmega644
+atmega644_isp: MCU_TARGET = atmega644p
+atmega644_isp: HFUSE = D8
+atmega644_isp: LFUSE = FF
+atmega644_isp: EFUSE = FF
+atmega644_isp: isp
+
+atmega328: TARGET = atmega328
+atmega328: MCU_TARGET = atmega328p
+atmega328: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600
+atmega328: AVR_FREQ = 16000000L
+atmega328: LDSECTION = --section-start=.text=0x7800
+atmega328: $(PROGRAM)_atmega328.hex
+
+atmega328_isp: atmega328
+atmega328_isp: TARGET = atmega328
+atmega328_isp: MCU_TARGET = atmega328p
+atmega328_isp: HFUSE = DA
+atmega328_isp: LFUSE = FF
+atmega328_isp: EFUSE = 05
+atmega328_isp: isp
+
+atmega328_notp: TARGET = atmega328_notp
+atmega328_notp: MCU_TARGET = atmega328
+atmega328_notp: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600
+atmega328_notp: AVR_FREQ = 16000000L
+atmega328_notp: LDSECTION = --section-start=.text=0x7800
+atmega328_notp: $(PROGRAM)_atmega328_notp.hex
+
+atmega328_notp_isp: atmega328_notp
+atmega328_notp_isp: TARGET = atmega328
+atmega328_notp_isp: MCU_TARGET = atmega328
+atmega328_notp_isp: HFUSE = DA
+atmega328_notp_isp: LFUSE = FF
+atmega328_notp_isp: EFUSE = 05
+atmega328_notp_isp: isp
+
+atmega328_pro8: TARGET = atmega328_pro_8MHz
+atmega328_pro8: MCU_TARGET = atmega328p
+atmega328_pro8: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -DDOUBLE_SPEED
+atmega328_pro8: AVR_FREQ = 8000000L
+atmega328_pro8: LDSECTION = --section-start=.text=0x7800
+atmega328_pro8: $(PROGRAM)_atmega328_pro_8MHz.hex
+
+atmega328_pro8_isp: atmega328_pro8
+atmega328_pro8_isp: TARGET = atmega328_pro_8MHz
+atmega328_pro8_isp: MCU_TARGET = atmega328p
+atmega328_pro8_isp: HFUSE = DA
+atmega328_pro8_isp: LFUSE = FF
+atmega328_pro8_isp: EFUSE = 05
+atmega328_pro8_isp: isp
+
+mega: TARGET = atmega1280
+mega: MCU_TARGET = atmega1280
+mega: CFLAGS += '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=0' -DBAUD_RATE=57600
+mega: AVR_FREQ = 16000000L
+mega: LDSECTION = --section-start=.text=0x1F000
+mega: $(PROGRAM)_atmega1280.hex
+
+mega_isp: mega
+mega_isp: TARGET = atmega1280
+mega_isp: MCU_TARGET = atmega1280
+mega_isp: HFUSE = DA
+mega_isp: LFUSE = FF
+mega_isp: EFUSE = F5
+mega_isp: isp
+
+isp: $(TARGET)
+ $(ISPFUSES)
+ $(ISPFLASH)
+
+isp-stk500: $(PROGRAM)_$(TARGET).hex
+ $(STK500-1)
+ $(STK500-2)
+
+%.elf: $(OBJ)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+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 -O ihex $< $@
+
+%.srec: %.elf
+ $(OBJCOPY) -j .text -j .data -O srec $< $@
+
+%.bin: %.elf
+ $(OBJCOPY) -j .text -j .data -O binary $< $@
+