aboutsummaryrefslogtreecommitdiff
path: root/bootloaders/optiboot/optiboot.c
diff options
context:
space:
mode:
authorWestfW <westfw@gmail.com>2011-06-10 16:17:13 -0700
committerDavid A. Mellis <d.mellis@arduino.cc>2011-10-10 12:11:14 -0400
commit67f1e949e184491161c91e44bf0393b8b90ab627 (patch)
tree1f87214102f781b4ff5778d88a6cdd7b3d669127 /bootloaders/optiboot/optiboot.c
parent8caed55a69858e26706dff31ff23e5be94bde669 (diff)
This is a relatively significant edit that brings the Arduino copy of
optiboot up-to-date with the optiboot source repository as of Jun-2011 (the last changes made in the optiboot repository were in Oct-2010) This adds support for several plaforms, fixes the "30k bug", and refactors the source to have separate stk500.h, boot.h, and pin_defs.h These are the arduino opticode issues fixed: http://code.google.com/p/arduino/issues/detail?id=380 optiboot has problems upload sketches bigger than 30 KB http://code.google.com/p/arduino/issues/detail?id=556 update optiboot to the point of the latest optiboot project sources. These are issues that had been solved in the optiboot source aready: http://code.google.com/p/arduino/issues/detail?id=364 optiboot leaves timer1 configured when starting app, breaks PWM on pin 9 and 10. (fixed with a workaround in arduino core.) aka http://code.google.com/p/optiboot/source/detail?r=c778fbe72df6ac13ef730c25283358c3c970f73e Support for ATmega8 and mega88. Fix fuse settings for mega168 _ISP targets Additional new platforms (mega, sanguino) http://code.google.com/p/optiboot/issues/detail?id=26 Set R1 to 0 (already in arduino code) http://code.google.com/p/optiboot/issues/detail?id=36&can=1 Fails to build correctly for mega88 After this commit, the only differences between the Arduino optiboot.c and the optiboot repository optiboot.c are cosmetic. (cherry picked from commit e2812ef91cc1489527827dcd14c843f3b3244f36)
Diffstat (limited to 'bootloaders/optiboot/optiboot.c')
-rw-r--r--bootloaders/optiboot/optiboot.c288
1 files changed, 176 insertions, 112 deletions
diff --git a/bootloaders/optiboot/optiboot.c b/bootloaders/optiboot/optiboot.c
index c7d817a..4b4a10a 100644
--- a/bootloaders/optiboot/optiboot.c
+++ b/bootloaders/optiboot/optiboot.c
@@ -1,6 +1,11 @@
/**********************************************************/
/* Optiboot bootloader for Arduino */
/* */
+/* http://optiboot.googlecode.com */
+/* */
+/* Arduino-maintained version : See README.TXT */
+/* http://code.google.com/p/arduino/ */
+/* */
/* Heavily optimised bootloader that is faster and */
/* smaller than the Arduino standard bootloader */
/* */
@@ -10,6 +15,8 @@
/* Higher baud rate speeds up programming */
/* Written almost entirely in C */
/* Customisable timeout with accurate timeconstant */
+/* Optional virtual UART. No hardware UART required. */
+/* Optional virtual boot partition for devices without. */
/* */
/* What you lose: */
/* Implements a skeleton STK500 protocol which is */
@@ -18,12 +25,19 @@
/* High baud rate breaks compatibility with standard */
/* Arduino flash settings */
/* */
-/* Currently supports: */
-/* ATmega168 based devices (Diecimila etc) */
+/* Fully supported: */
+/* ATmega168 based devices (Diecimila etc) */
/* ATmega328P based devices (Duemilanove etc) */
/* */
+/* Alpha test */
+/* ATmega1280 based devices (Arduino Mega) */
+/* */
+/* Work in progress: */
+/* ATmega644P based devices (Sanguino) */
+/* ATtiny84 based devices (Luminet) */
+/* */
/* Does not support: */
-/* ATmega1280 based devices (eg. Mega) */
+/* USB based devices (eg. Teensy) */
/* */
/* Assumptions: */
/* The code makes several assumptions that reduce the */
@@ -64,102 +78,85 @@
/* */
/**********************************************************/
+
+/**********************************************************/
+/* */
+/* Optional defines: */
+/* */
+/**********************************************************/
+/* */
+/* BIG_BOOT: */
+/* Build a 1k bootloader, not 512 bytes. This turns on */
+/* extra functionality. */
+/* */
+/* BAUD_RATE: */
+/* Set bootloader baud rate. */
+/* */
+/* LUDICROUS_SPEED: */
+/* 230400 baud :-) */
+/* */
+/* SOFT_UART: */
+/* Use AVR305 soft-UART instead of hardware UART. */
+/* */
+/* LED_START_FLASHES: */
+/* Number of LED flashes on bootup. */
+/* */
+/* LED_DATA_FLASH: */
+/* Flash LED when transferring data. For boards without */
+/* TX or RX LEDs, or for people who like blinky lights. */
+/* */
+/* SUPPORT_EEPROM: */
+/* Support reading and writing from EEPROM. This is not */
+/* used by Arduino, so off by default. */
+/* */
+/* TIMEOUT_MS: */
+/* Bootloader timeout period, in milliseconds. */
+/* 500,1000,2000,4000,8000 supported. */
+/* */
+/**********************************************************/
+
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
-#include <avr/boot.h>
-//#define LED_DATA_FLASH
+// <avr/boot.h> uses sts instructions, but this version uses out instructions
+// This saves cycles and program memory.
+#include "boot.h"
+
+
+// We don't use <avr/wdt.h> as those routines have interrupt overhead we don't need.
+
+#include "pin_defs.h"
+#include "stk500.h"
#ifndef LED_START_FLASHES
#define LED_START_FLASHES 0
#endif
-/* Build-time variables */
-/* BAUD_RATE Programming baud rate */
-/* LED_NO_FLASHES Number of LED flashes on boot */
-/* FLASH_TIME_MS Duration of each LED flash */
-/* BOOT_TIMEOUT_MS Serial port wait time before exiting bootloader */
+#ifdef LUDICROUS_SPEED
+#define BAUD_RATE 230400L
+#endif
-/* set the UART baud rate */
+/* set the UART baud rate defaults */
#ifndef BAUD_RATE
-#define BAUD_RATE 19200
+#if F_CPU >= 8000000L
+#define BAUD_RATE 115200L // Highest rate Avrdude win32 will support
+#elsif F_CPU >= 1000000L
+#define BAUD_RATE 9600L // 19200 also supported, but with significant error
+#elsif F_CPU >= 128000L
+#define BAUD_RATE 4800L // Good for 128kHz internal RC
+#else
+#define BAUD_RATE 1200L // Good even at 32768Hz
+#endif
#endif
-#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
-/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
-#define LED_DDR DDRB
-#define LED_PORT PORTB
-#define LED_PIN PINB
-#define LED PINB5
-
-/* Ports for soft UART */
-#ifdef SOFT_UART
-#define UART_PORT PORTD
-#define UART_PIN PIND
-#define UART_DDR DDRD
-#define UART_TX_BIT 1
-#define UART_RX_BIT 0
+/* Switch in soft UART for hard baud rates */
+#if (F_CPU/BAUD_RATE) > 280 // > 57600 for 16MHz
+#ifndef SOFT_UART
+#define SOFT_UART
#endif
#endif
-#if defined(__AVR_ATtiny84__)
-/* Onboard LED is connected to pin PB5 in Arduino NG, Diecimila, and Duemilanove */
-#define LED_DDR DDRA
-#define LED_PORT PORTA
-#define LED_PIN PINA
-#define LED PINA4
-
-/* Ports for soft UART - left port only for now*/
-#ifdef SOFT_UART
-#define UART_PORT PORTA
-#define UART_PIN PINA
-#define UART_DDR DDRA
-#define UART_TX_BIT 2
-#define UART_RX_BIT 3
-#endif
-#endif
-
-/* STK500 constants list, from AVRDUDE */
-#define STK_OK 0x10
-#define STK_FAILED 0x11 // Not used
-#define STK_UNKNOWN 0x12 // Not used
-#define STK_NODEVICE 0x13 // Not used
-#define STK_INSYNC 0x14 // ' '
-#define STK_NOSYNC 0x15 // Not used
-#define ADC_CHANNEL_ERROR 0x16 // Not used
-#define ADC_MEASURE_OK 0x17 // Not used
-#define PWM_CHANNEL_ERROR 0x18 // Not used
-#define PWM_ADJUST_OK 0x19 // Not used
-#define CRC_EOP 0x20 // 'SPACE'
-#define STK_GET_SYNC 0x30 // '0'
-#define STK_GET_SIGN_ON 0x31 // '1'
-#define STK_SET_PARAMETER 0x40 // '@'
-#define STK_GET_PARAMETER 0x41 // 'A'
-#define STK_SET_DEVICE 0x42 // 'B'
-#define STK_SET_DEVICE_EXT 0x45 // 'E'
-#define STK_ENTER_PROGMODE 0x50 // 'P'
-#define STK_LEAVE_PROGMODE 0x51 // 'Q'
-#define STK_CHIP_ERASE 0x52 // 'R'
-#define STK_CHECK_AUTOINC 0x53 // 'S'
-#define STK_LOAD_ADDRESS 0x55 // 'U'
-#define STK_UNIVERSAL 0x56 // 'V'
-#define STK_PROG_FLASH 0x60 // '`'
-#define STK_PROG_DATA 0x61 // 'a'
-#define STK_PROG_FUSE 0x62 // 'b'
-#define STK_PROG_LOCK 0x63 // 'c'
-#define STK_PROG_PAGE 0x64 // 'd'
-#define STK_PROG_FUSE_EXT 0x65 // 'e'
-#define STK_READ_FLASH 0x70 // 'p'
-#define STK_READ_DATA 0x71 // 'q'
-#define STK_READ_FUSE 0x72 // 'r'
-#define STK_READ_LOCK 0x73 // 's'
-#define STK_READ_PAGE 0x74 // 't'
-#define STK_READ_SIGN 0x75 // 'u'
-#define STK_READ_OSCCAL 0x76 // 'v'
-#define STK_READ_FUSE_EXT 0x77 // 'w'
-#define STK_READ_OSCCAL_EXT 0x78 // 'x'
-
/* Watchdog settings */
#define WATCHDOG_OFF (0)
#define WATCHDOG_16MS (_BV(WDE))
@@ -170,8 +167,10 @@
#define WATCHDOG_500MS (_BV(WDP2) | _BV(WDP0) | _BV(WDE))
#define WATCHDOG_1S (_BV(WDP2) | _BV(WDP1) | _BV(WDE))
#define WATCHDOG_2S (_BV(WDP2) | _BV(WDP1) | _BV(WDP0) | _BV(WDE))
+#ifndef __AVR_ATmega8__
#define WATCHDOG_4S (_BV(WDE3) | _BV(WDE))
#define WATCHDOG_8S (_BV(WDE3) | _BV(WDE0) | _BV(WDE))
+#endif
/* Function Prototypes */
/* The main function is in init9, which removes the interrupt vector table */
@@ -191,18 +190,41 @@ void uartDelay() __attribute__ ((naked));
#endif
void appStart() __attribute__ ((naked));
+#if defined(__AVR_ATmega168__)
+#define RAMSTART (0x100)
+#define NRWWSTART (0x3800)
+#elif defined(__AVR_ATmega328P__)
+#define RAMSTART (0x100)
+#define NRWWSTART (0x7000)
+#elif defined (__AVR_ATmega644P__)
+#define RAMSTART (0x100)
+#define NRWWSTART (0xE000)
+#elif defined(__AVR_ATtiny84__)
+#define RAMSTART (0x100)
+#define NRWWSTART (0x0000)
+#elif defined(__AVR_ATmega1280__)
+#define RAMSTART (0x200)
+#define NRWWSTART (0xE000)
+#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__)
+#define RAMSTART (0x100)
+#define NRWWSTART (0x1800)
+#endif
+
/* C zero initialises all global variables. However, that requires */
/* These definitions are NOT zero initialised, but that doesn't matter */
/* This allows us to drop the zero init code, saving us memory */
-#define buff ((uint8_t*)(0x100))
-#define address (*(uint16_t*)(0x200))
-#define length (*(uint8_t*)(0x202))
+#define buff ((uint8_t*)(RAMSTART))
+#define address (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2))
+#define length (*(uint8_t*)(RAMSTART+SPM_PAGESIZE*2+2))
#ifdef VIRTUAL_BOOT_PARTITION
-#define rstVect (*(uint16_t*)(0x204))
-#define wdtVect (*(uint16_t*)(0x206))
+#define rstVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+4))
+#define wdtVect (*(uint16_t*)(RAMSTART+SPM_PAGESIZE*2+6))
#endif
+
/* main program starts here */
int main(void) {
+ uint8_t ch;
+
// After the zero init loop, this is the first code to run.
//
// This code makes the following assumptions:
@@ -212,29 +234,36 @@ int main(void) {
//
// If not, uncomment the following instructions:
// cli();
- // SP=RAMEND; // This is done by hardware reset
asm volatile ("clr __zero_reg__");
+#ifdef __AVR_ATmega8__
+ SP=RAMEND; // This is done by hardware reset
+#endif
- uint8_t ch;
+ // Adaboot no-wait mod
+ ch = MCUSR;
+ MCUSR = 0;
+ if (!(ch & _BV(EXTRF))) appStart();
#if LED_START_FLASHES > 0
// Set up Timer 1 for timeout counter
TCCR1B = _BV(CS12) | _BV(CS10); // div 1024
#endif
#ifndef SOFT_UART
+#ifdef __AVR_ATmega8__
+ UCSRA = _BV(U2X); //Double speed mode USART
+ UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx
+ UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1
+ UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
+#else
UCSR0A = _BV(U2X0); //Double speed mode USART0
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 );
#endif
-
- // Adaboot no-wait mod
- ch = MCUSR;
- MCUSR = 0;
- if (!(ch & _BV(EXTRF))) appStart();
+#endif
// Set up watchdog to trigger after 500ms
- watchdogConfig(WATCHDOG_500MS);
+ watchdogConfig(WATCHDOG_1S);
/* Set LED pin as output */
LED_DDR |= _BV(LED);
@@ -269,9 +298,15 @@ int main(void) {
}
else if(ch == STK_LOAD_ADDRESS) {
// LOAD ADDRESS
- address = getch();
- address = (address & 0xff) | (getch() << 8);
- address += address; // Convert from word address to byte address
+ uint16_t newAddress;
+ newAddress = getch();
+ newAddress = (newAddress & 0xff) | (getch() << 8);
+#ifdef RAMPZ
+ // Transfer top bit to RAMPZ
+ RAMPZ = (newAddress & 0x8000) ? 1 : 0;
+#endif
+ newAddress += newAddress; // Convert from word address to byte address
+ address = newAddress;
verifySpace();
}
else if(ch == STK_UNIVERSAL) {
@@ -279,7 +314,7 @@ int main(void) {
getNch(4);
putch(0x00);
}
- /* Write memory, length is big endian and is in bytes */
+ /* Write memory, length is big endian and is in bytes */
else if(ch == STK_PROG_PAGE) {
// PROGRAM PAGE - we support flash programming only, not EEPROM
uint8_t *bufPtr;
@@ -287,14 +322,18 @@ int main(void) {
getLen();
- // Immediately start page erase - this will 4.5ms
- boot_page_erase((uint16_t)(void*)address);
-
+ // If we are in RWW section, immediately start page erase
+ if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
+
// While that is going on, read in page contents
bufPtr = buff;
do *bufPtr++ = getch();
while (--length);
+ // If we are in NRWW section, page erase has to be delayed until now.
+ // Todo: Take RAMPZ into account
+ if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
+
// Read command terminator, start reply
verifySpace();
@@ -310,10 +349,10 @@ int main(void) {
// Move RESET vector to WDT vector
uint16_t vect = buff[0] | (buff[1]<<8);
rstVect = vect;
- wdtVect = buff[10] | (buff[11]<<8);
+ wdtVect = buff[8] | (buff[9]<<8);
vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
- buff[10] = vect & 0xff;
- buff[11] = vect >> 8;
+ buff[8] = vect & 0xff;
+ buff[9] = vect >> 8;
// Add jump to bootloader at RESET vector
buff[0] = 0x7f;
@@ -329,12 +368,12 @@ int main(void) {
uint16_t a;
a = *bufPtr++;
a |= (*bufPtr++) << 8;
- boot_page_fill((uint16_t)(void*)addrPtr,a);
+ __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
addrPtr += 2;
} while (--ch);
// Write from programming buffer
- boot_page_write((uint16_t)(void*)address);
+ __boot_page_write_short((uint16_t)(void*)address);
boot_spm_busy_wait();
#if defined(RWWSRE)
@@ -353,16 +392,28 @@ int main(void) {
// Undo vector patch in bottom page so verify passes
if (address == 0) ch=rstVect & 0xff;
else if (address == 1) ch=rstVect >> 8;
- else if (address == 10) ch=wdtVect & 0xff;
- else if (address == 11) ch=wdtVect >> 8;
+ else if (address == 8) ch=wdtVect & 0xff;
+ else if (address == 9) ch=wdtVect >> 8;
else ch = pgm_read_byte_near(address);
address++;
putch(ch);
} while (--length);
#else
+#ifdef __AVR_ATmega1280__
+// do putch(pgm_read_byte_near(address++));
+// while (--length);
+ do {
+ uint8_t result;
+ __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
+ putch(result);
+ address++;
+ }
+ while (--length);
+#else
do putch(pgm_read_byte_near(address++));
while (--length);
#endif
+#endif
}
/* Get device signature bytes */
@@ -422,8 +473,12 @@ uint8_t getch(void) {
watchdogReset();
#ifdef LED_DATA_FLASH
+#ifdef __AVR_ATmega8__
+ LED_PORT ^= _BV(LED);
+#else
LED_PIN |= _BV(LED);
#endif
+#endif
#ifdef SOFT_UART
__asm__ __volatile__ (
@@ -455,14 +510,19 @@ uint8_t getch(void) {
#endif
#ifdef LED_DATA_FLASH
+#ifdef __AVR_ATmega8__
+ LED_PORT ^= _BV(LED);
+#else
LED_PIN |= _BV(LED);
#endif
+#endif
return ch;
}
#ifdef SOFT_UART
-//#define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
+// AVR350 equation: #define UART_B_VALUE (((F_CPU/BAUD_RATE)-23)/6)
+// Adding 3 to numerator simulates nearest rounding for more accurate baud rates
#define UART_B_VALUE (((F_CPU/BAUD_RATE)-20)/6)
#if UART_B_VALUE > 255
#error Baud rate too slow for soft UART
@@ -495,7 +555,11 @@ void flash_led(uint8_t count) {
TCNT1 = -(F_CPU/(1024*16));
TIFR1 = _BV(TOV1);
while(!(TIFR1 & _BV(TOV1)));
+#ifdef __AVR_ATmega8__
+ LED_PORT ^= _BV(LED);
+#else
LED_PIN |= _BV(LED);
+#endif
watchdogReset();
} while (--count);
}
@@ -524,7 +588,7 @@ void appStart() {
__asm__ __volatile__ (
#ifdef VIRTUAL_BOOT_PARTITION
// Jump to WDT vector
- "ldi r30,5\n"
+ "ldi r30,4\n"
"clr r31\n"
#else
// Jump to RST vector