You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							389 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
	
	
							389 lines
						
					
					
						
							10 KiB
						
					
					
				| /**********************************************************/
 | |
| /* Serial Bootloader for Atmel megaAVR Controllers        */
 | |
| /*                                                        */
 | |
| /* tested with ATmega644 and ATmega644P                   */
 | |
| /* should work with other mega's, see code for details    */
 | |
| /*                                                        */
 | |
| /* ATmegaBOOT.c                                           */
 | |
| /*                                                        */
 | |
| /* 20090131: Added 324P support from Alex Leone           */
 | |
| /*           Marius Kintel                                */
 | |
| /* 20080915: applied ADABoot mods for Sanguino 644P       */
 | |
| /*           Brian Riley                                  */
 | |
| /* 20080711: hacked for Sanguino by Zach Smith            */
 | |
| /*           and Justin Day                               */
 | |
| /* 20070626: hacked for Arduino Diecimila (which auto-    */
 | |
| /*           resets when a USB connection is made to it)  */
 | |
| /*           by D. Mellis                                 */
 | |
| /* 20060802: hacked for Arduino by D. Cuartielles         */
 | |
| /*           based on a previous hack by D. Mellis        */
 | |
| /*           and D. Cuartielles                           */
 | |
| /*                                                        */
 | |
| /* Monitor and debug functions were added to the original */
 | |
| /* code by Dr. Erik Lins, chip45.com. (See below)         */
 | |
| /*                                                        */
 | |
| /* Thanks to Karl Pitrich for fixing a bootloader pin     */
 | |
| /* problem and more informative LED blinking!             */
 | |
| /*                                                        */
 | |
| /* For the latest version see:                            */
 | |
| /* http://www.chip45.com/                                 */
 | |
| /*                                                        */
 | |
| /* ------------------------------------------------------ */
 | |
| /*                                                        */
 | |
| /* based on stk500boot.c                                  */
 | |
| /* Copyright (c) 2003, Jason P. Kyle                      */
 | |
| /* All rights reserved.                                   */
 | |
| /* see avr1.org for original file and information         */
 | |
| /*                                                        */
 | |
| /* This program is free software; you can redistribute it */
 | |
| /* and/or modify it under the terms of the GNU General    */
 | |
| /* Public License as published by the Free Software       */
 | |
| /* Foundation; either version 2 of the License, or        */
 | |
| /* (at your option) any later version.                    */
 | |
| /*                                                        */
 | |
| /* This program is distributed in the hope that it will   */
 | |
| /* be useful, but WITHOUT ANY WARRANTY; without even the  */
 | |
| /* implied warranty of MERCHANTABILITY or FITNESS FOR A   */
 | |
| /* PARTICULAR PURPOSE.  See the GNU General Public        */
 | |
| /* License for more details.                              */
 | |
| /*                                                        */
 | |
| /* You should have received a copy of the GNU General     */
 | |
| /* Public License along with this program; if not, write  */
 | |
| /* to the Free Software Foundation, Inc.,                 */
 | |
| /* 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
 | |
| /*                                                        */
 | |
| /* Licence can be viewed at                               */
 | |
| /* http://www.fsf.org/licenses/gpl.txt                    */
 | |
| /*                                                        */
 | |
| /* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
 | |
| /* m8515,m8535. ATmega161 has a very small boot block so  */
 | |
| /* isn't supported.                                       */
 | |
| /*                                                        */
 | |
| /* Tested with m168                                       */
 | |
| /**********************************************************/
 | |
| 
 | |
| /* $Id$ */
 | |
| 
 | |
| 
 | |
| /* some includes */
 | |
| #include <inttypes.h>
 | |
| #include <avr/io.h>
 | |
| #include <avr/pgmspace.h>
 | |
| #include <avr/interrupt.h>
 | |
| #include <avr/wdt.h>
 | |
| #include <avr/boot.h>
 | |
| #include <util/delay.h>
 | |
| 
 | |
| #ifdef ADABOOT
 | |
|     #define NUM_LED_FLASHES 3
 | |
|     #define ADABOOT_VER	1
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */
 | |
| #define MAX_ERROR_COUNT 5
 | |
| 
 | |
| /* set the UART baud rate */
 | |
| /* 20080711: hack by Zach Hoeken */
 | |
| #define BAUD_RATE   38400
 | |
| 
 | |
| /* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
 | |
| /* never allow AVR Studio to do an update !!!! */
 | |
| #define HW_VER	 0x02
 | |
| #define SW_MAJOR 0x01
 | |
| #define SW_MINOR 0x10
 | |
| 
 | |
| /* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */
 | |
| /* if monitor functions are included, LED goes on after monitor was entered */
 | |
| #define LED_DDR  DDRB
 | |
| #define LED_PORT PORTB
 | |
| #define LED_PIN  PINB
 | |
| #define LED      PINB0
 | |
| 
 | |
| /* define various device id's */
 | |
| /* manufacturer byte is always the same */
 | |
| #define SIG1	0x1E	// Yep, Atmel is the only manufacturer of AVR micros.  Single source :(
 | |
| #if defined(__AVR_ATmega1284P__)
 | |
| #define SIG2	0x97
 | |
| #define SIG3	0x05
 | |
| #elif defined(__AVR_ATmega644P__)
 | |
| #define SIG2	0x96
 | |
| #define SIG3	0x0A
 | |
| #elif defined(__AVR_ATmega644__)
 | |
| #define SIG2	0x96
 | |
| #define SIG3	0x09
 | |
| #elif defined(__AVR_ATmega324P__)
 | |
| #define SIG2	0x95
 | |
| #define SIG3	0x08
 | |
| #endif
 | |
| #define PAGE_SIZE		0x080U   //128 words
 | |
| #define PAGE_SIZE_BYTES	0x100U   //256 bytes
 | |
| 
 | |
| /* function prototypes */
 | |
| void putch(char);
 | |
| char getch(void);
 | |
| void getNch(uint8_t);
 | |
| void byte_response(uint8_t);
 | |
| void nothing_response(void);
 | |
| char gethex(void);
 | |
| void puthex(char);
 | |
| void flash_led(uint8_t);
 | |
| 
 | |
| /* some variables */
 | |
| union address_union
 | |
| {
 | |
|     uint16_t word;
 | |
|     uint8_t  byte[2];
 | |
| } address;
 | |
| 
 | |
| union length_union
 | |
| {
 | |
|     uint16_t word;
 | |
|     uint8_t  byte[2];
 | |
| } length;
 | |
| 
 | |
| struct flags_struct
 | |
| {
 | |
|     unsigned eeprom : 1;
 | |
|     unsigned rampz  : 1;
 | |
| } flags;
 | |
| 
 | |
| uint8_t buff[256];
 | |
| 
 | |
| uint8_t error_count = 0;
 | |
| uint8_t sreg;
 | |
| 
 | |
| void (*app_start)(void) = 0x0000;
 | |
| 
 | |
| /* main program starts here */
 | |
| int main(void)
 | |
| {
 | |
|     uint8_t ch,ch2;
 | |
|     uint16_t w;
 | |
| 	uint16_t i;
 | |
| 	
 | |
|     asm volatile("nop\n\t");
 | |
| 
 | |
| #ifdef ADABOOT		// BBR/LF 10/8/2007 & 9/13/2008
 | |
|     ch = MCUSR;
 | |
|     MCUSR = 0;
 | |
| 
 | |
|     WDTCSR |= _BV(WDCE) | _BV(WDE);
 | |
|     WDTCSR = 0;
 | |
| 
 | |
|     // Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.
 | |
|     if (! (ch &  _BV(EXTRF))) // if it's a not an external reset...
 | |
|       app_start();  // skip bootloader
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	//initialize our serial port.
 | |
|     UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
 | |
|     UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
 | |
|     UCSR0B = (1<<RXEN0) | (1<<TXEN0);
 | |
|     UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
 | |
| 
 | |
|     /* Enable internal pull-up resistor on pin D0 (RX), in order
 | |
|     to supress line noise that prevents the bootloader from
 | |
|     timing out (DAM: 20070509) */
 | |
|     DDRD &= ~_BV(PIND0);
 | |
|     PORTD |= _BV(PIND0);
 | |
| 
 | |
|     /* set LED pin as output */
 | |
|     LED_DDR |= _BV(LED);
 | |
| 
 | |
| 	    /* flash onboard LED to signal entering of bootloader                   */
 | |
| 	    /* ADABOOT will do two series of flashes. first 4 - signifying ADABOOT  */
 | |
| 	    /* then a pause and another flash series signifying ADABOOT sub-version */
 | |
| 
 | |
| 
 | |
| 	flash_led(NUM_LED_FLASHES);
 | |
| 
 | |
| 	#ifdef	ADABOOT
 | |
| 		flash_led(ADABOOT_VER);		// BBR 9/13/2008
 | |
| 	#endif 
 | |
| 
 | |
|     /* forever loop */
 | |
|     for (;;)
 | |
| 	{
 | |
|           putch('\r');
 | |
|           _delay_ms(500);
 | |
|         }
 | |
|     /* end of forever loop */
 | |
| }
 | |
| 
 | |
| 
 | |
| char gethex(void)
 | |
| {
 | |
|     char ah,al;
 | |
| 
 | |
|     ah = getch();
 | |
| 	putch(ah);
 | |
|     al = getch();
 | |
| 	putch(al);
 | |
|     
 | |
| 	if(ah >= 'a')
 | |
| 		ah = ah - 'a' + 0x0a;
 | |
| 	else if(ah >= '0')
 | |
| 		ah -= '0';
 | |
|     if(al >= 'a')
 | |
| 		al = al - 'a' + 0x0a;
 | |
| 	else if(al >= '0')
 | |
| 		al -= '0';
 | |
| 
 | |
|     return (ah << 4) + al;
 | |
| }
 | |
| 
 | |
| 
 | |
| void puthex(char ch)
 | |
| {
 | |
|     char ah,al;
 | |
| 
 | |
|     ah = (ch & 0xf0) >> 4;
 | |
| 	if(ah >= 0x0a)
 | |
| 		ah = ah - 0x0a + 'a';
 | |
| 	else
 | |
| 		ah += '0';
 | |
| 
 | |
|     al = (ch & 0x0f);
 | |
| 	if(al >= 0x0a)
 | |
| 		al = al - 0x0a + 'a';
 | |
| 	else
 | |
| 		al += '0';
 | |
| 
 | |
|     putch(ah);
 | |
|     putch(al);
 | |
| }
 | |
| 
 | |
| 
 | |
| void putch(char ch)
 | |
| {
 | |
|     while (!(UCSR0A & _BV(UDRE0)));
 | |
|     UDR0 = ch;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| char getch(void)
 | |
| {
 | |
|     uint32_t count = 0;
 | |
| 
 | |
| #ifdef ADABOOT
 | |
| 	LED_PORT &= ~_BV(LED);          // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
 | |
| #endif
 | |
| 
 | |
|     while(!(UCSR0A & _BV(RXC0)))
 | |
| 	{
 | |
|     	/* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/               
 | |
|     	/* HACKME:: here is a good place to count times*/
 | |
|     	count++;
 | |
|     	if (count > MAX_TIME_COUNT)
 | |
|     		app_start();
 | |
|      }
 | |
| 
 | |
| #ifdef ADABOOT
 | |
| 	LED_PORT |= _BV(LED);          // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
 | |
| #endif
 | |
| 
 | |
|     return UDR0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void getNch(uint8_t count)
 | |
| {
 | |
|     uint8_t i;
 | |
|     for(i=0;i<count;i++)
 | |
| 	{
 | |
| 		while(!(UCSR0A & _BV(RXC0)));
 | |
| 		UDR0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void byte_response(uint8_t val)
 | |
| {
 | |
|     if (getch() == ' ')
 | |
| 	{
 | |
| 		putch(0x14);
 | |
| 		putch(val);
 | |
| 		putch(0x10);
 | |
|     }
 | |
| 	else
 | |
| 	{
 | |
| 		if (++error_count == MAX_ERROR_COUNT)
 | |
| 		    app_start();
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| void nothing_response(void)
 | |
| {
 | |
|     if (getch() == ' ')
 | |
| 	{
 | |
| 		putch(0x14);
 | |
| 		putch(0x10);
 | |
|     }
 | |
| 	else
 | |
| 	{
 | |
| 		if (++error_count == MAX_ERROR_COUNT)
 | |
| 		    app_start();
 | |
|     }
 | |
| }
 | |
| 
 | |
| #ifdef ADABOOT
 | |
| 
 | |
| void flash_led(uint8_t count)
 | |
| {
 | |
|     /* flash onboard LED count times to signal entering of bootloader */
 | |
| 	/* l needs to be volatile or the delay loops below might get      */
 | |
| 	/* optimized away if compiling with optimizations (DAM).          */
 | |
| 	
 | |
|     volatile uint32_t l;
 | |
| 
 | |
|     if (count == 0) {
 | |
|       count = ADABOOT;
 | |
|     }
 | |
|     
 | |
| 
 | |
| 	int8_t i;
 | |
|     for (i = 0; i < count; ++i) {
 | |
| 		LED_PORT |= _BV(LED);					// LED on
 | |
| 		for(l = 0; l < (F_CPU / 1000); ++l);		// delay NGvalue was 1000 for both loops - BBR
 | |
| 		LED_PORT &= ~_BV(LED);					// LED off
 | |
| 		for(l = 0; l < (F_CPU / 250); ++l);		// delay asymmteric for ADA BOOT BBR 
 | |
| 	}
 | |
| 
 | |
| 	for(l = 0; l < (F_CPU / 100); ++l);		    // pause ADA BOOT BBR 
 | |
| 		
 | |
| }
 | |
| 
 | |
| #else
 | |
| 
 | |
| void flash_led(uint8_t count)
 | |
| {
 | |
|     /* flash onboard LED three times to signal entering of bootloader */
 | |
| 	/* l needs to be volatile or the delay loops below might get
 | |
| 	optimized away if compiling with optimizations (DAM). */
 | |
|     volatile uint32_t l;
 | |
| 
 | |
|     if (count == 0) {
 | |
|       count = 3;
 | |
|     }
 | |
|     
 | |
| 	int8_t i;
 | |
|     for (i = 0; i < count; ++i) {
 | |
| 		LED_PORT |= _BV(LED);
 | |
| 		for(l = 0; l < (F_CPU / 1000); ++l);
 | |
| 		LED_PORT &= ~_BV(LED);
 | |
| 		for(l = 0; l < (F_CPU / 1000); ++l); 
 | |
| 	}
 | |
| 		
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 
 | |
| /* end of file ATmegaBOOT.c */
 |