/***************************************************************************** Title: STK500v2 compatible bootloader Modified for Wiring board ATMega128-16MHz Author: Peter Fleury http://jump.to/fleury Compiler: avr-gcc 3.4.5 or 4.1 / avr-libc 1.4.3 Hardware: All AVRs with bootloader support, tested with ATmega8 License: GNU General Public License Modified: Worapoht Kornkaewwattanakul http://www.avride.com Date: 17 October 2007 Update: 1st, 29 Dec 2007 : Enable CMD_SPI_MULTI but ignore unused command by return 0x00 byte response.. Compiler: WINAVR20060421 Description: add timeout feature like previous Wiring bootloader DESCRIPTION: This program allows an AVR with bootloader capabilities to read/write its own Flash/EEprom. To enter Programming mode an input pin is checked. If this pin is pulled low, programming mode is entered. If not, normal execution is done from $0000 "reset" vector in Application area. Size fits into a 1024 word bootloader section when compiled with avr-gcc 4.1 (direct replace on Wiring Board without fuse setting changed) USAGE: - Set AVR MCU type and clock-frequency (F_CPU) in the Makefile. - Set baud rate below (AVRISP only works with 115200 bps) - compile/link the bootloader with the supplied Makefile - program the "Boot Flash section size" (BOOTSZ fuses), for boot-size 1024 words: program BOOTSZ01 - enable the BOOT Reset Vector (program BOOTRST) - Upload the hex file to the AVR using any ISP programmer - Program Boot Lock Mode 3 (program BootLock 11 and BootLock 12 lock bits) // (leave them) - Reset your AVR while keeping PROG_PIN pulled low // (for enter bootloader by switch) - Start AVRISP Programmer (AVRStudio/Tools/Program AVR) - AVRISP will detect the bootloader - Program your application FLASH file and optional EEPROM file using AVRISP Note: Erasing the device without flashing, through AVRISP GUI button "Erase Device" is not implemented, due to AVRStudio limitations. Flash is always erased before programming. AVRdude: Please uncomment #define REMOVE_CMD_SPI_MULTI when using AVRdude. Comment #define REMOVE_PROGRAM_LOCK_BIT_SUPPORT to reduce code size Read Fuse Bits and Read/Write Lock Bits is not supported NOTES: Based on Atmel Application Note AVR109 - Self-programming Based on Atmel Application Note AVR068 - STK500v2 Protocol LICENSE: Copyright (C) 2006 Peter Fleury 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 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. *****************************************************************************/ //************************************************************************ //* Edit History //************************************************************************ //* Jul 7, 2010 = Mark Sproul msproul@skycharoit.com //* Jul 7, 2010 Working on mega2560. No Auto-restart //* Jul 7, 2010 Switched to 8K bytes (4K words) so that we have room for the monitor //* Jul 8, 2010 Found older version of source that had auto restart, put that code back in //* Jul 8, 2010 Adding monitor code //* Jul 11, 2010 Added blinking LED while waiting for download to start //* Jul 11, 2010 Added EEPROM test //* Jul 29, 2010 Added recchar_timeout for timing out on bootloading //* Aug 23, 2010 Added support for atmega2561 //* Aug 26, 2010 Removed support for BOOT_BY_SWITCH //* Sep 8, 2010 Added support for atmega16 //* Nov 9, 2010 Issue 392:Fixed bug that 3 !!! in code would cause it to jump to monitor //* Jun 24, 2011 Removed analogRead (was not used) //* Dec 29, 2011 Issue 181: added watch dog timmer support //* Dec 29, 2011 Issue 505: bootloader is comparing the seqNum to 1 or the current sequence //* Jan 1, 2012 Issue 543: CMD_CHIP_ERASE_ISP now returns STATUS_CMD_FAILED instead of STATUS_CMD_OK //* Jan 1, 2012 Issue 543: Write EEPROM now does something (NOT TESTED) //* Jan 1, 2012 Issue 544: stk500v2 bootloader doesn't support reading fuses //************************************************************************ //************************************************************************ //* these are used to test issues //* http://code.google.com/p/arduino/issues/detail?id=505 //* Reported by mark.stubbs, Mar 14, 2011 //* The STK500V2 bootloader is comparing the seqNum to 1 or the current sequence //* (IE: Requiring the sequence to be 1 or match seqNum before continuing). //* The correct behavior is for the STK500V2 to accept the PC's sequence number, and echo it back for the reply message. #define _FIX_ISSUE_505_ //************************************************************************ //* Issue 181: added watch dog timmer support #define _FIX_ISSUE_181_ // LCD startup screen and boot animation #define LCD_HD44780 #define LCD_HD44780_ANIMATION #define LCD_HD44780_COUNTER // Dual serial support #define DUALSERIAL // EINSY board #define EINSYBOARD #include #include #include #include #include #include #include #include #include "command.h" #ifdef LCD_HD44780 #include "lcd.h" #endif #ifndef EEWE #define EEWE 1 #endif #ifndef EEMWE #define EEMWE 2 #endif /* * Uncomment the following lines to save code space */ //#define REMOVE_PROGRAM_LOCK_BIT_SUPPORT // disable program lock bits //#define REMOVE_BOOTLOADER_LED // no LED to show active bootloader //#define REMOVE_CMD_SPI_MULTI // disable processing of SPI_MULTI commands, Remark this line for AVRDUDE // //************************************************************************ //* LED on pin "PROGLED_PIN" on port "PROGLED_PORT" //* indicates that bootloader is active //* PG2 -> LED on Wiring board //************************************************************************ #define BLINK_LED_WHILE_WAITING #ifdef _MEGA_BOARD_ #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB7 #elif defined( _BOARD_AMBER128_ ) //* this is for the amber 128 http://www.soc-robotics.com/ //* onbarod led is PORTE4 #define PROGLED_PORT PORTD #define PROGLED_DDR DDRD #define PROGLED_PIN PINE7 #elif defined( _CEREBOTPLUS_BOARD_ ) || defined(_CEREBOT_II_BOARD_) //* this is for the Cerebot 2560 board and the Cerebot-ii //* onbarod leds are on PORTE4-7 #define PROGLED_PORT PORTE #define PROGLED_DDR DDRE #define PROGLED_PIN PINE7 #elif defined( _PENGUINO_ ) //* this is for the Penguino //* onbarod led is PORTE4 #define PROGLED_PORT PORTC #define PROGLED_DDR DDRC #define PROGLED_PIN PINC6 #elif defined( _ANDROID_2561_ ) || defined( __AVR_ATmega2561__ ) //* this is for the Boston Android 2561 //* onbarod led is PORTE4 #define PROGLED_PORT PORTA #define PROGLED_DDR DDRA #define PROGLED_PIN PINA3 #elif defined( _BOARD_MEGA16 ) //* onbarod led is PORTA7 #define PROGLED_PORT PORTA #define PROGLED_DDR DDRA #define PROGLED_PIN PINA7 #define UART_BAUDRATE_DOUBLE_SPEED 0 #elif defined( _BOARD_BAHBOT_ ) //* dosent have an onboard LED but this is what will probably be added to this port #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB0 #elif defined( _BOARD_ROBOTX_ ) #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB6 #elif defined( _BOARD_CUSTOM1284_BLINK_B0_ ) #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB0 #elif defined( _BOARD_CUSTOM1284_ ) #define PROGLED_PORT PORTD #define PROGLED_DDR DDRD #define PROGLED_PIN PIND5 #elif defined( _AVRLIP_ ) #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB5 #elif defined( _BOARD_STK500_ ) #define PROGLED_PORT PORTA #define PROGLED_DDR DDRA #define PROGLED_PIN PINA7 #elif defined( _BOARD_STK502_ ) #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB5 #elif defined( _BOARD_STK525_ ) #define PROGLED_PORT PORTB #define PROGLED_DDR DDRB #define PROGLED_PIN PINB7 #else #define PROGLED_PORT PORTG #define PROGLED_DDR DDRG #define PROGLED_PIN PING2 #endif /* * define CPU frequency in Mhz here if not defined in Makefile */ #ifndef F_CPU #define F_CPU 16000000UL #endif #define _BLINK_LOOP_COUNT_ (F_CPU / 2250) /* * UART Baudrate, AVRStudio AVRISP only accepts 115200 bps */ #ifndef BAUDRATE #define BAUDRATE 115200 #endif /* * Enable (1) or disable (0) USART double speed operation */ #ifndef UART_BAUDRATE_DOUBLE_SPEED #if defined (__AVR_ATmega32__) #define UART_BAUDRATE_DOUBLE_SPEED 0 #else #define UART_BAUDRATE_DOUBLE_SPEED 1 #endif #endif /* * HW and SW version, reported to AVRISP, must match version of AVRStudio */ #define CONFIG_PARAM_BUILD_NUMBER_LOW 0 #define CONFIG_PARAM_BUILD_NUMBER_HIGH 0 #define CONFIG_PARAM_HW_VER 0x0F #define CONFIG_PARAM_SW_MAJOR 2 #define CONFIG_PARAM_SW_MINOR 0x0A /* * Calculate the address where the bootloader starts from FLASHEND and BOOTSIZE * (adjust BOOTSIZE below and BOOTLOADER_ADDRESS in Makefile if you want to change the size of the bootloader) */ //#define BOOTSIZE 1024 #if FLASHEND > 0x0F000 #define BOOTSIZE 8192 #else #define BOOTSIZE 2048 #endif //#define APP_END (FLASHEND -(2*BOOTSIZE) + 1) #define APP_END (FLASHEND -(BOOTSIZE) + 1) /* * Signature bytes are not available in avr-gcc io_xxx.h */ #if defined (__AVR_ATmega8__) #define SIGNATURE_BYTES 0x1E9307 #elif defined (__AVR_ATmega16__) #define SIGNATURE_BYTES 0x1E9403 #elif defined (__AVR_ATmega32__) #define SIGNATURE_BYTES 0x1E9502 #elif defined (__AVR_ATmega8515__) #define SIGNATURE_BYTES 0x1E9306 #elif defined (__AVR_ATmega8535__) #define SIGNATURE_BYTES 0x1E9308 #elif defined (__AVR_ATmega162__) #define SIGNATURE_BYTES 0x1E9404 #elif defined (__AVR_ATmega128__) #define SIGNATURE_BYTES 0x1E9702 #elif defined (__AVR_ATmega1280__) #define SIGNATURE_BYTES 0x1E9703 #elif defined (__AVR_ATmega2560__) #define SIGNATURE_BYTES 0x1E9801 #elif defined (__AVR_ATmega2561__) #define SIGNATURE_BYTES 0x1e9802 #elif defined (__AVR_ATmega1284P__) #define SIGNATURE_BYTES 0x1e9705 #elif defined (__AVR_ATmega640__) #define SIGNATURE_BYTES 0x1e9608 #elif defined (__AVR_ATmega64__) #define SIGNATURE_BYTES 0x1E9602 #elif defined (__AVR_ATmega169__) #define SIGNATURE_BYTES 0x1e9405 #elif defined (__AVR_AT90USB1287__) #define SIGNATURE_BYTES 0x1e9782 #else #error "no signature definition for MCU available" #endif #if defined(_BOARD_ROBOTX_) || defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) #define UART_BAUD_RATE_LOW UBRR1L #define UART_STATUS_REG UCSR1A #define UART_CONTROL_REG UCSR1B #define UART_ENABLE_TRANSMITTER TXEN1 #define UART_ENABLE_RECEIVER RXEN1 #define UART_TRANSMIT_COMPLETE TXC1 #define UART_RECEIVE_COMPLETE RXC1 #define UART_DATA_REG UDR1 #define UART_DOUBLE_SPEED U2X1 #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) /* ATMega8 with one USART */ #define UART_BAUD_RATE_LOW UBRRL #define UART_STATUS_REG UCSRA #define UART_CONTROL_REG UCSRB #define UART_ENABLE_TRANSMITTER TXEN #define UART_ENABLE_RECEIVER RXEN #define UART_TRANSMIT_COMPLETE TXC #define UART_RECEIVE_COMPLETE RXC #define UART_DATA_REG UDR #define UART_DOUBLE_SPEED U2X #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega162__) \ || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) /* ATMega with two USART, use UART0 */ #define UART_BAUD_RATE_LOW UBRR0L #define UART_STATUS_REG UCSR0A #define UART_CONTROL_REG UCSR0B #define UART_ENABLE_TRANSMITTER TXEN0 #define UART_ENABLE_RECEIVER RXEN0 #define UART_TRANSMIT_COMPLETE TXC0 #define UART_RECEIVE_COMPLETE RXC0 #define UART_DATA_REG UDR0 #define UART_DOUBLE_SPEED U2X0 #elif defined(UBRR0L) && defined(UCSR0A) && defined(TXEN0) /* ATMega with two USART, use UART0 */ #define UART_BAUD_RATE_LOW UBRR0L #define UART_STATUS_REG UCSR0A #define UART_CONTROL_REG UCSR0B #define UART_ENABLE_TRANSMITTER TXEN0 #define UART_ENABLE_RECEIVER RXEN0 #define UART_TRANSMIT_COMPLETE TXC0 #define UART_RECEIVE_COMPLETE RXC0 #define UART_DATA_REG UDR0 #define UART_DOUBLE_SPEED U2X0 #elif defined(UBRRL) && defined(UCSRA) && defined(UCSRB) && defined(TXEN) && defined(RXEN) //* catch all #define UART_BAUD_RATE_LOW UBRRL #define UART_STATUS_REG UCSRA #define UART_CONTROL_REG UCSRB #define UART_ENABLE_TRANSMITTER TXEN #define UART_ENABLE_RECEIVER RXEN #define UART_TRANSMIT_COMPLETE TXC #define UART_RECEIVE_COMPLETE RXC #define UART_DATA_REG UDR #define UART_DOUBLE_SPEED U2X #else #error "no UART definition for MCU available" #endif /* * Macro to calculate UBBR from XTAL and baudrate */ #if defined(__AVR_ATmega32__) && UART_BAUDRATE_DOUBLE_SPEED #define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu / 4 / baudRate - 1) / 2) #elif defined(__AVR_ATmega32__) #define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu / 8 / baudRate - 1) / 2) #elif UART_BAUDRATE_DOUBLE_SPEED #define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*8.0)-1.0+0.5) #else #define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*16.0)-1.0+0.5) #endif #ifdef DUALSERIAL // UART defines #define UART_BAUD_RATE_LOW0 UBRR0L #define UART_STATUS_REG0 UCSR0A #define UART_CONTROL_REG0 UCSR0B #define UART_ENABLE_TRANSMITTER0 TXEN0 #define UART_ENABLE_RECEIVER0 RXEN0 #define UART_TRANSMIT_COMPLETE0 TXC0 #define UART_RECEIVE_COMPLETE0 RXC0 #define UART_DATA_REG0 UDR0 #define UART_DOUBLE_SPEED0 U2X0 #define UART_BAUD_RATE_LOW2 UBRR2L #define UART_STATUS_REG2 UCSR2A #define UART_CONTROL_REG2 UCSR2B #define UART_ENABLE_TRANSMITTER2 TXEN2 #define UART_ENABLE_RECEIVER2 RXEN2 #define UART_TRANSMIT_COMPLETE2 TXC2 #define UART_RECEIVE_COMPLETE2 RXC2 #define UART_DATA_REG2 UDR2 #define UART_DOUBLE_SPEED2 U2X2 #endif //DUALSERIAL #define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*8.0)-1.0+0.5) /* * States used in the receive state machine */ #define ST_START 0 #define ST_GET_SEQ_NUM 1 #define ST_MSG_SIZE_1 2 #define ST_MSG_SIZE_2 3 #define ST_GET_TOKEN 4 #define ST_GET_DATA 5 #define ST_GET_CHECK 6 #define ST_PROCESS 7 /* * use 16bit address variable for ATmegas with <= 64K flash */ #if defined(RAMPZ) typedef uint32_t address_t; #else typedef uint16_t address_t; #endif /* * function prototypes */ static void sendchar(char c); //static unsigned char recchar(void); #ifdef DUALSERIAL int selectedSerial; #endif //DUALSERIAL /* * since this bootloader is not linked against the avr-gcc crt1 functions, * to reduce the code size, we need to provide our own initialization */ void __jumpMain (void) __attribute__ ((naked)) __attribute__ ((section (".init9"))); #include //#define SPH_REG 0x3E //#define SPL_REG 0x3D #define STACK_TOP (RAMEND - 16) //***************************************************************************** void __jumpMain(void) { //* July 17, 2010 Added stack pointer initialzation //* the first line did not do the job on the ATmega128 asm volatile ( ".set __stack, %0" :: "i" (STACK_TOP) ); //* set stack pointer to top of RAM asm volatile ( "ldi 16, %0" :: "i" (STACK_TOP >> 8) ); asm volatile ( "out %0,16" :: "i" (AVR_STACK_POINTER_HI_ADDR) ); asm volatile ( "ldi 16, %0" :: "i" (STACK_TOP & 0x0ff) ); asm volatile ( "out %0,16" :: "i" (AVR_STACK_POINTER_LO_ADDR) ); asm volatile ( "clr __zero_reg__" ); // GCC depends on register r1 set to 0 asm volatile ( "out %0, __zero_reg__" :: "I" (_SFR_IO_ADDR(SREG)) ); // set SREG to 0 asm volatile ( "jmp main"); // jump to main() } //***************************************************************************** void delay_ms(unsigned int timedelay) { unsigned int i; for (i=0;i 9)?('A' + val - 10):('0' + val)); } void lcd_print_hex_byte(uint8_t val) { lcd_print_hex_nibble(val >> 4); lcd_print_hex_nibble(val & 0xf); } void lcd_print_hex_word(uint16_t val) { lcd_print_hex_byte(val >> 8); lcd_print_hex_byte(val & 0xff); } void lcd_print_hex_dword(uint32_t val) { lcd_print_hex_word(val >> 16); lcd_print_hex_word(val & 0xffff); } /**/ /* const unsigned long ulFlashEnd = FLASHEND; const unsigned long ulRamEnd = RAMEND; const unsigned long ulBootSize = BOOTSIZE; const unsigned long ulAppEnd = APP_END; */ //***************************************************************************** /* * send single byte to USART, wait until transmission is completed */ static void sendchar(char c) { #ifdef DUALSERIAL if (selectedSerial == 0) { UART_DATA_REG0 = c; // prepare transmission while (!(UART_STATUS_REG0 & (1 << UART_TRANSMIT_COMPLETE0))); // wait until byte sent UART_STATUS_REG0 |= (1 << UART_TRANSMIT_COMPLETE0); // delete TXCflag } else if (selectedSerial == 2) { UART_DATA_REG2 = c; // prepare transmission while (!(UART_STATUS_REG2 & (1 << UART_TRANSMIT_COMPLETE2))); // wait until byte sent UART_STATUS_REG2 |= (1 << UART_TRANSMIT_COMPLETE2); // delete TXCflag } #else //DUALSERIAL UART_DATA_REG = c; // prepare transmission while (!(UART_STATUS_REG & (1 << UART_TRANSMIT_COMPLETE))); // wait until byte sent UART_STATUS_REG |= (1 << UART_TRANSMIT_COMPLETE); // delete TXCflag #endif //DUALSERIAL } //************************************************************************ #ifdef DUALSERIAL static int Serial_Available(int serial) { if (serial == 0) return (UART_STATUS_REG0 & (1 << UART_RECEIVE_COMPLETE0)); // wait for data else if (serial == 2) return (UART_STATUS_REG2 & (1 << UART_RECEIVE_COMPLETE2)); // wait for data return 0; } #else //DUALSERIAL static int Serial_Available(void) { return (UART_STATUS_REG & (1 << UART_RECEIVE_COMPLETE)); // wait for data } #endif //DUALSERIAL //***************************************************************************** /* * Read single byte from USART, block if no data available */ /*static unsigned char recchar(void) { #ifdef DUALSERIAL if (selectedSerial == 0) { while (!(UART_STATUS_REG0 & (1 << UART_RECEIVE_COMPLETE0))) { } // wait for data return UART_DATA_REG0; } else if (selectedSerial == 2) { while (!(UART_STATUS_REG2 & (1 << UART_RECEIVE_COMPLETE2))) { } // wait for data return UART_DATA_REG2; } return 0; #else //DUALSERIAL while (!(UART_STATUS_REG & (1 << UART_RECEIVE_COMPLETE))) { } // wait for data return UART_DATA_REG; #endif //DUALSERIAL }*/ #define MAX_TIME_COUNT (F_CPU >> 1) //***************************************************************************** static unsigned char recchar_timeout(void) { uint32_t count = 0; #ifdef DUALSERIAL while (1) { if ((selectedSerial == 0) && (UART_STATUS_REG0 & (1 << UART_RECEIVE_COMPLETE0))) break; else if ((selectedSerial == 2) && (UART_STATUS_REG2 & (1 << UART_RECEIVE_COMPLETE2))) break; count++; if (count > MAX_TIME_COUNT) { unsigned int data; #if (FLASHEND > 0x10000) data = pgm_read_word_far(0); //* get the first word of the user program #else data = pgm_read_word_near(0); //* get the first word of the user program #endif if (data != 0xffff) //* make sure its valid before jumping to it. { asm volatile( "clr r30 \n\t" "clr r31 \n\t" "ijmp \n\t" ); } count = 0; } } if (selectedSerial == 0) return UART_DATA_REG0; else if (selectedSerial == 2) return UART_DATA_REG2; return 0; #else //DUALSERIAL while (!(UART_STATUS_REG & (1 << UART_RECEIVE_COMPLETE))) { // wait for data count++; if (count > MAX_TIME_COUNT) { unsigned int data; #if (FLASHEND > 0x10000) data = pgm_read_word_far(0); //* get the first word of the user program #else data = pgm_read_word_near(0); //* get the first word of the user program #endif if (data != 0xffff) //* make sure its valid before jumping to it. { asm volatile( "clr r30 \n\t" "clr r31 \n\t" "ijmp \n\t" ); } count = 0; } } return UART_DATA_REG; #endif //DUALSERIAL } #ifdef DUALSERIAL void initUart() { // init uart0 UART_STATUS_REG0 |= (1 <> 8) ); asm volatile ( "out %0,16" :: "i" (AVR_STACK_POINTER_HI_ADDR) ); asm volatile ( "ldi 16, %0" :: "i" (RAMEND & 0x0ff) ); asm volatile ( "out %0,16" :: "i" (AVR_STACK_POINTER_LO_ADDR) );*/ #ifdef _FIX_ISSUE_181_ //************************************************************************ //* Dec 29, 2011 Issue #181, added watch dog timmer support //* handle the watch dog timer uint8_t mcuStatusReg; mcuStatusReg = MCUSR; __asm__ __volatile__ ("cli"); __asm__ __volatile__ ("wdr"); MCUSR = 0; WDTCSR |= _BV(WDCE) | _BV(WDE); WDTCSR = 0; __asm__ __volatile__ ("sei"); // check if WDT generated the reset, if so, go straight to app if (mcuStatusReg & _BV(WDRF)) { if (boot_app_magic == 0x55aa55aa) { /// uint16_t tmp_boot_copy_size = boot_copy_size; /// uint32_t tmp_boot_src_addr = boot_src_addr; address = boot_dst_addr; address_t pageAddress = address; while (boot_copy_size) { if (boot_app_flags & BOOT_APP_FLG_ERASE) { boot_page_erase(pageAddress); boot_spm_busy_wait(); } pageAddress += SPM_PAGESIZE; if ((boot_app_flags & BOOT_APP_FLG_COPY)) { while (boot_copy_size && (address < pageAddress)) { uint16_t word = 0x0000; if (boot_app_flags & BOOT_APP_FLG_FLASH) word = pgm_read_word_far(boot_src_addr); //from FLASH else word = *((uint16_t*)boot_src_addr); //from RAM boot_page_fill(address, word); address += 2; boot_src_addr += 2; if (boot_copy_size > 2) boot_copy_size -= 2; else boot_copy_size = 0; } boot_page_write(pageAddress - SPM_PAGESIZE); boot_spm_busy_wait(); boot_rww_enable(); } else { address += SPM_PAGESIZE; if (boot_copy_size > SPM_PAGESIZE) boot_copy_size -= SPM_PAGESIZE; else boot_copy_size = 0; } } /// boot_copy_size = tmp_boot_copy_size; /// boot_src_addr = tmp_boot_src_addr; } goto exit; // original implementation app_start() does not work // app_start(); } //************************************************************************ #endif boot_timer = 0; boot_state = 0; #ifdef BLINK_LED_WHILE_WAITING // boot_timeout = 90000; //* should be about 4 seconds // boot_timeout = 170000; boot_timeout = 20000; //* should be about 1 second #else boot_timeout = 3500000; // 7 seconds , approx 2us per step when optimize "s" #endif /* * Branch to bootloader or application code ? */ #ifdef DUALSERIAL selectedSerial = 0; #endif //DUALSERIAL #ifndef REMOVE_BOOTLOADER_LED /* PROG_PIN pulled low, indicate with LED that bootloader is active */ PROGLED_DDR |= (1< boot_timeout) { boot_state = 1; // (after ++ -> boot_state=2 bootloader timeout, jump to main 0x00000 ) } #ifdef BLINK_LED_WHILE_WAITING if ((boot_timer % _BLINK_LOOP_COUNT_) == 0) { //* toggle the LED PROGLED_PORT ^= (1< boot_timeout) { boot_state = 1; // (after ++ -> boot_state=2 bootloader timeout, jump to main 0x00000 ) } #ifdef BLINK_LED_WHILE_WAITING if ((boot_timer % _BLINK_LOOP_COUNT_) == 0) { //* toggle the LED PROGLED_PORT ^= (1< 10) { animationTimer = 0; animationFrame++; if (animationFrame > 5) animationFrame = 0; lcd_goto(91); lcd_puts("| |"); lcd_goto((animationFrame <= 3)?(92 + animationFrame):(98 - animationFrame)); lcd_putc('*'); } } #endif //LCD_HD44780_ANIMATION #ifdef LCD_HD44780_COUNTER if ((flashSize != 0) && flashOperation) { if (flashOperation == 1) //write { lcd_goto(88); lcd_puts("write "); } if (flashOperation == 2) //verify { lcd_goto(87); lcd_puts("verify "); } int progress = 100 * flashCounter / flashSize; char text[4] = " "; for (int i = 2; i >= 0; i--) if (progress > 0) { text[i] = '0' + (progress % 10); progress /= 10; } else text[i] = ' '; lcd_puts(text); lcd_putc('%'); } #endif //LCD_HD44780_COUNTER /* * Now process the STK500 commands, see Atmel Appnote AVR068 */ switch (msgBuffer[0]) { #ifndef REMOVE_CMD_SPI_MULTI case CMD_SPI_MULTI: { unsigned char answerByte; unsigned char flag=0; if ( msgBuffer[4]== 0x30 ) { unsigned char signatureIndex = msgBuffer[6]; if ( signatureIndex == 0 ) { answerByte = (SIGNATURE_BYTES >> 16) & 0x000000FF; } else if ( signatureIndex == 1 ) { answerByte = (SIGNATURE_BYTES >> 8) & 0x000000FF; } else { answerByte = SIGNATURE_BYTES & 0x000000FF; } } else if ( msgBuffer[4] & 0x50 ) { //* Issue 544: stk500v2 bootloader doesn't support reading fuses //* I cant find the docs that say what these are supposed to be but this was figured out by trial and error // answerByte = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS); // answerByte = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); // answerByte = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS); if (msgBuffer[4] == 0x50) { answerByte = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS); } else if (msgBuffer[4] == 0x58) { answerByte = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); } else { answerByte = 0; } } else { answerByte = 0; // for all others command are not implemented, return dummy value for AVRDUDE happy } if ( !flag ) { msgLength = 7; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = 0; msgBuffer[3] = msgBuffer[4]; msgBuffer[4] = 0; msgBuffer[5] = answerByte; msgBuffer[6] = STATUS_CMD_OK; } } break; #endif case CMD_SIGN_ON: msgLength = 11; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = 8; msgBuffer[3] = 'A'; msgBuffer[4] = 'V'; msgBuffer[5] = 'R'; msgBuffer[6] = 'I'; msgBuffer[7] = 'S'; msgBuffer[8] = 'P'; msgBuffer[9] = '_'; msgBuffer[10] = '2'; break; case CMD_GET_PARAMETER: { unsigned char value; switch(msgBuffer[1]) { case PARAM_BUILD_NUMBER_LOW: value = CONFIG_PARAM_BUILD_NUMBER_LOW; break; case PARAM_BUILD_NUMBER_HIGH: value = CONFIG_PARAM_BUILD_NUMBER_HIGH; break; case PARAM_HW_VER: value = CONFIG_PARAM_HW_VER; break; case PARAM_SW_MAJOR: value = CONFIG_PARAM_SW_MAJOR; break; case PARAM_SW_MINOR: value = CONFIG_PARAM_SW_MINOR; break; default: value = 0; break; } msgLength = 3; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = value; } break; case CMD_LEAVE_PROGMODE_ISP: isLeave = 1; //* fall thru case CMD_SET_PARAMETER: case CMD_ENTER_PROGMODE_ISP: msgLength = 2; msgBuffer[1] = STATUS_CMD_OK; break; case CMD_READ_SIGNATURE_ISP: { unsigned char signatureIndex = msgBuffer[4]; unsigned char signature; if ( signatureIndex == 0 ) signature = (SIGNATURE_BYTES >>16) & 0x000000FF; else if ( signatureIndex == 1 ) signature = (SIGNATURE_BYTES >> 8) & 0x000000FF; else signature = SIGNATURE_BYTES & 0x000000FF; msgLength = 4; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = signature; msgBuffer[3] = STATUS_CMD_OK; } break; case CMD_READ_LOCK_ISP: msgLength = 4; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = boot_lock_fuse_bits_get( GET_LOCK_BITS ); msgBuffer[3] = STATUS_CMD_OK; break; case CMD_READ_FUSE_ISP: { unsigned char fuseBits; if ( msgBuffer[2] == 0x50 ) { if ( msgBuffer[3] == 0x08 ) fuseBits = boot_lock_fuse_bits_get( GET_EXTENDED_FUSE_BITS ); else fuseBits = boot_lock_fuse_bits_get( GET_LOW_FUSE_BITS ); } else { fuseBits = boot_lock_fuse_bits_get( GET_HIGH_FUSE_BITS ); } msgLength = 4; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = fuseBits; msgBuffer[3] = STATUS_CMD_OK; } break; #ifndef REMOVE_PROGRAM_LOCK_BIT_SUPPORT case CMD_PROGRAM_LOCK_ISP: { unsigned char lockBits = msgBuffer[4]; lockBits = (~lockBits) & 0x3C; // mask BLBxx bits boot_lock_bits_set(lockBits); // and program it boot_spm_busy_wait(); msgLength = 3; msgBuffer[1] = STATUS_CMD_OK; msgBuffer[2] = STATUS_CMD_OK; } break; #endif case CMD_CHIP_ERASE_ISP: eraseAddress = 0; msgLength = 2; // msgBuffer[1] = STATUS_CMD_OK; msgBuffer[1] = STATUS_CMD_FAILED; //* isue 543, return FAILED instead of OK break; case CMD_LOAD_ADDRESS: #if defined(RAMPZ) address = ( ((address_t)(msgBuffer[1])<<24)|((address_t)(msgBuffer[2])<<16)|((address_t)(msgBuffer[3])<<8)|(msgBuffer[4]) )<<1; #else address = ( ((msgBuffer[3])<<8)|(msgBuffer[4]) )<<1; //convert word to byte address #endif msgLength = 2; msgBuffer[1] = STATUS_CMD_OK; break; case CMD_SET_UPLOAD_SIZE_PRUSA3D: ((unsigned char*)&flashSize)[0] = msgBuffer[1]; ((unsigned char*)&flashSize)[1] = msgBuffer[2]; ((unsigned char*)&flashSize)[2] = msgBuffer[3]; ((unsigned char*)&flashSize)[3] = 0; msgLength = 2; msgBuffer[1] = STATUS_CMD_OK; break; case CMD_PROGRAM_FLASH_ISP: case CMD_PROGRAM_EEPROM_ISP: { unsigned int size = ((msgBuffer[1])<<8) | msgBuffer[2]; unsigned char *p = msgBuffer+10; unsigned int data; unsigned char highByte, lowByte; address_t tempaddress = address; if ( msgBuffer[0] == CMD_PROGRAM_FLASH_ISP ) { if (flashSize != 0) { if (address == 0) //first page { flashCounter = size; //initial value = size flashAddressLast = 0; //last flashOperation = 1; //write } else if (address != flashAddressLast) flashCounter += size; //add size to counter flashAddressLast = address; } // erase only main section (bootloader protection) if (eraseAddress < APP_END ) //erase and write only blocks with address less 0x3e000 { //because prevent "brick" boot_page_erase(eraseAddress); // Perform page erase boot_spm_busy_wait(); // Wait until the memory is erased. eraseAddress += SPM_PAGESIZE; // point to next page to be erase } if (address < APP_END) { /* Write FLASH */ do { lowByte = *p++; highByte = *p++; data = (highByte << 8) | lowByte; boot_page_fill(address,data); address = address + 2; // Select next word in memory size -= 2; // Reduce number of bytes to write by two } while (size); // Loop until all bytes written boot_page_write(tempaddress); boot_spm_busy_wait(); boot_rww_enable(); // Re-enable the RWW section } } else { //* issue 543, this should work, It has not been tested. uint16_t ii = address >> 1; /* write EEPROM */ while (size) { eeprom_write_byte((uint8_t*)ii, *p++); address+=2; // Select next EEPROM byte ii++; size--; } } msgLength = 2; msgBuffer[1] = STATUS_CMD_OK; } break; case CMD_READ_FLASH_ISP: case CMD_READ_EEPROM_ISP: { unsigned int size = ((msgBuffer[1])<<8) | msgBuffer[2]; unsigned char *p = msgBuffer+1; msgLength = size+3; *p++ = STATUS_CMD_OK; if (msgBuffer[0] == CMD_READ_FLASH_ISP ) { if (flashSize != 0) { if ((address == 0x00000) && (flashOperation == 1)) { flashOperation = 2; //verify flashCounter = size; //initial value = size } else flashCounter += size; //add size to counter } unsigned int data; // Read FLASH do { //#if defined(RAMPZ) #if (FLASHEND > 0x10000) data = pgm_read_word_far(address); #else data = pgm_read_word_near(address); #endif *p++ = (unsigned char)data; //LSB *p++ = (unsigned char)(data >> 8); //MSB address += 2; // Select next word in memory size -= 2; }while (size); } else { /* Read EEPROM */ do { EEARL = address; // Setup EEPROM address EEARH = ((address >> 8)); address++; // Select next EEPROM byte EECR |= (1<>8)&0xFF); sendchar(c); checksum ^= c; c = msgLength&0x00FF; sendchar(c); checksum ^= c; sendchar(TOKEN); checksum ^= TOKEN; p = msgBuffer; while ( msgLength ) { c = *p++; sendchar(c); checksum ^=c; msgLength--; } sendchar(checksum); seqNum++; #ifndef REMOVE_BOOTLOADER_LED //* toggle the LED PROGLED_PORT ^= (1< base address = f000 avrdude: Device signature = 0x1e9703 avrdude: safemode: lfuse reads as FF avrdude: safemode: hfuse reads as D8 avrdude: safemode: efuse reads as F5 avrdude> */ //************************************************************************