|
@@ -154,6 +154,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -224,8 +236,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-#define OPTIBOOT_MAJVER 6
|
|
+#define OPTIBOOT_MAJVER 7
|
|
-#define OPTIBOOT_MINVER 2
|
|
+#define OPTIBOOT_MINVER 0
|
|
|
|
|
|
|
|
|
|
* OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
|
|
* OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
|
|
@@ -246,6 +258,20 @@ optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER;
|
|
#include <avr/pgmspace.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <avr/eeprom.h>
|
|
#include <avr/eeprom.h>
|
|
|
|
|
|
|
|
+
|
|
|
|
+ * optiboot uses several "address" variables that are sometimes byte pointers,
|
|
|
|
+ * sometimes word pointers. sometimes 16bit quantities, and sometimes built
|
|
|
|
+ * up from 8bit input characters. avr-gcc is not great at optimizing the
|
|
|
|
+ * assembly of larger words from bytes, but we can use the usual union to
|
|
|
|
+ * do this manually. Expanding it a little, we can also get rid of casts.
|
|
|
|
+ */
|
|
|
|
+typedef union {
|
|
|
|
+ uint8_t *bptr;
|
|
|
|
+ uint16_t *wptr;
|
|
|
|
+ uint16_t word;
|
|
|
|
+ uint8_t bytes[2];
|
|
|
|
+} addr16_t;
|
|
|
|
+
|
|
|
|
|
|
* Note that we use our own version of "boot.h"
|
|
* Note that we use our own version of "boot.h"
|
|
* <avr/boot.h> uses sts instructions, but this version uses out instructions
|
|
* <avr/boot.h> uses sts instructions, but this version uses out instructions
|
|
@@ -364,10 +390,10 @@ static inline void getNch(uint8_t);
|
|
static inline void flash_led(uint8_t);
|
|
static inline void flash_led(uint8_t);
|
|
#endif
|
|
#endif
|
|
static inline void watchdogReset();
|
|
static inline void watchdogReset();
|
|
-static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
|
|
+static inline void writebuffer(int8_t memtype, addr16_t mybuff,
|
|
- uint16_t address, pagelen_t len);
|
|
+ addr16_t address, pagelen_t len);
|
|
static inline void read_mem(uint8_t memtype,
|
|
static inline void read_mem(uint8_t memtype,
|
|
- uint16_t address, pagelen_t len);
|
|
+ addr16_t, pagelen_t len);
|
|
|
|
|
|
#ifdef SOFT_UART
|
|
#ifdef SOFT_UART
|
|
void uartDelay() __attribute__ ((naked));
|
|
void uartDelay() __attribute__ ((naked));
|
|
@@ -394,7 +420,7 @@ void appStart(uint8_t rstFlags) __attribute__ ((naked));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-#define buff ((uint8_t*)(RAMSTART))
|
|
+static addr16_t buff = {(uint8_t *)(RAMSTART)};
|
|
|
|
|
|
|
|
|
|
#ifdef VIRTUAL_BOOT_PARTITION
|
|
#ifdef VIRTUAL_BOOT_PARTITION
|
|
@@ -454,7 +480,7 @@ int main(void) {
|
|
* (initializing address keeps the compiler happy, but isn't really
|
|
* (initializing address keeps the compiler happy, but isn't really
|
|
* necessary, and uses 4 bytes of flash.)
|
|
* necessary, and uses 4 bytes of flash.)
|
|
*/
|
|
*/
|
|
- register uint16_t address = 0;
|
|
+ register addr16_t address;
|
|
register pagelen_t length;
|
|
register pagelen_t length;
|
|
|
|
|
|
|
|
|
|
@@ -472,20 +498,48 @@ int main(void) {
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
- * modified Adaboot no-wait mod.
|
|
+ * Protect as much from MCUSR as possible for application
|
|
- * Pass the reset reason to app. Also, it appears that an Uno poweron
|
|
+ * and still skip bootloader if not necessary
|
|
- * can leave multiple reset flags set; we only want the bootloader to
|
|
+ *
|
|
- * run on an 'external reset only' status
|
|
+ * Code by MarkG55
|
|
|
|
+ * see discusion in https:
|
|
*/
|
|
*/
|
|
#if !defined(__AVR_ATmega16__)
|
|
#if !defined(__AVR_ATmega16__)
|
|
ch = MCUSR;
|
|
ch = MCUSR;
|
|
- MCUSR = 0;
|
|
|
|
#else
|
|
#else
|
|
ch = MCUCSR;
|
|
ch = MCUCSR;
|
|
- MCUCSR = 0;
|
|
|
|
#endif
|
|
#endif
|
|
- if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF)))
|
|
+
|
|
- appStart(ch);
|
|
+ if (ch != 0) {
|
|
|
|
+
|
|
|
|
+ * To run the boot loader, External Reset Flag must be set.
|
|
|
|
+ * If not, we could make shortcut and jump directly to application code.
|
|
|
|
+ * Also WDRF set with EXTRF is a result of Optiboot timeout, so we
|
|
|
|
+ * shouldn't run bootloader in loop :-) That's why:
|
|
|
|
+ * 1. application is running if WDRF is cleared
|
|
|
|
+ * 2. we clear WDRF if it's set with EXTRF to avoid loops
|
|
|
|
+ * One problematic scenario: broken application code sets watchdog timer
|
|
|
|
+ * without clearing MCUSR before and triggers it quickly. But it's
|
|
|
|
+ * recoverable by power-on with pushed reset button.
|
|
|
|
+ */
|
|
|
|
+ if ((ch & (_BV(WDRF) | _BV(EXTRF))) != _BV(EXTRF)) {
|
|
|
|
+ if (ch & _BV(EXTRF)) {
|
|
|
|
+
|
|
|
|
+ * Clear WDRF because it was most probably set by wdr in bootloader.
|
|
|
|
+ * It's also needed to avoid loop by broken application which could
|
|
|
|
+ * prevent entering bootloader.
|
|
|
|
+ * '&' operation is skipped to spare few bytes as bits in MCUSR
|
|
|
|
+ * can only be cleared.
|
|
|
|
+ */
|
|
|
|
+#if !defined(__AVR_ATmega16__)
|
|
|
|
+ MCUSR = ~(_BV(WDRF));
|
|
|
|
+#else
|
|
|
|
+ MCUCSR = ~(_BV(WDRF));
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ appStart(ch);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
#if LED_START_FLASHES > 0
|
|
#if LED_START_FLASHES > 0
|
|
|
|
|
|
@@ -509,7 +563,7 @@ int main(void) {
|
|
|
|
|
|
watchdogConfig(WATCHDOG_1S);
|
|
watchdogConfig(WATCHDOG_1S);
|
|
|
|
|
|
-#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH)
|
|
+#if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) || defined(LED_START_ON)
|
|
|
|
|
|
LED_DDR |= _BV(LED);
|
|
LED_DDR |= _BV(LED);
|
|
#endif
|
|
#endif
|
|
@@ -522,6 +576,11 @@ int main(void) {
|
|
#if LED_START_FLASHES > 0
|
|
#if LED_START_FLASHES > 0
|
|
|
|
|
|
flash_led(LED_START_FLASHES * 2);
|
|
flash_led(LED_START_FLASHES * 2);
|
|
|
|
+#else
|
|
|
|
+#if defined(LED_START_ON)
|
|
|
|
+
|
|
|
|
+ LED_PORT |= _BV(LED);
|
|
|
|
+#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -558,20 +617,18 @@ int main(void) {
|
|
}
|
|
}
|
|
else if(ch == STK_LOAD_ADDRESS) {
|
|
else if(ch == STK_LOAD_ADDRESS) {
|
|
|
|
|
|
- uint16_t newAddress;
|
|
+ address.bytes[0] = getch();
|
|
- newAddress = getch();
|
|
+ address.bytes[1] = getch();
|
|
- newAddress = (newAddress & 0xff) | (getch() << 8);
|
|
|
|
#ifdef RAMPZ
|
|
#ifdef RAMPZ
|
|
|
|
|
|
- if (newAddress & 0x8000) {
|
|
+ if (address.bytes[1] & 0x80) {
|
|
RAMPZ |= 0x01;
|
|
RAMPZ |= 0x01;
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
RAMPZ &= 0xFE;
|
|
RAMPZ &= 0xFE;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
- newAddress += newAddress;
|
|
+ address.word *= 2;
|
|
- address = newAddress;
|
|
|
|
verifySpace();
|
|
verifySpace();
|
|
}
|
|
}
|
|
else if(ch == STK_UNIVERSAL) {
|
|
else if(ch == STK_UNIVERSAL) {
|
|
@@ -608,7 +665,7 @@ int main(void) {
|
|
desttype = getch();
|
|
desttype = getch();
|
|
|
|
|
|
|
|
|
|
- bufPtr = buff;
|
|
+ bufPtr = buff.bptr;
|
|
do *bufPtr++ = getch();
|
|
do *bufPtr++ = getch();
|
|
while (--length);
|
|
while (--length);
|
|
|
|
|
|
@@ -621,51 +678,55 @@ int main(void) {
|
|
* AVR with 4-byte ISR Vectors and "jmp"
|
|
* AVR with 4-byte ISR Vectors and "jmp"
|
|
* WARNING: this works only up to 128KB flash!
|
|
* WARNING: this works only up to 128KB flash!
|
|
*/
|
|
*/
|
|
- if (address == 0) {
|
|
+ if (address.word == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- rstVect0_sav = buff[rstVect0];
|
|
+ rstVect0_sav = buff.bptr[rstVect0];
|
|
- rstVect1_sav = buff[rstVect1];
|
|
+ rstVect1_sav = buff.bptr[rstVect1];
|
|
- saveVect0_sav = buff[saveVect0];
|
|
+ saveVect0_sav = buff.bptr[saveVect0];
|
|
- saveVect1_sav = buff[saveVect1];
|
|
+ saveVect1_sav = buff.bptr[saveVect1];
|
|
|
|
|
|
|
|
|
|
- buff[saveVect0] = rstVect0_sav;
|
|
+ buff.bptr[saveVect0] = rstVect0_sav;
|
|
- buff[saveVect1] = rstVect1_sav;
|
|
+ buff.bptr[saveVect1] = rstVect1_sav;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- buff[rstVect0] = ((uint16_t)main) & 0xFF;
|
|
+ buff.bptr[rstVect0] = ((uint16_t)main) & 0xFF;
|
|
- buff[rstVect1] = ((uint16_t)main) >> 8;
|
|
+ buff.bptr[rstVect1] = ((uint16_t)main) >> 8;
|
|
}
|
|
}
|
|
|
|
|
|
#else
|
|
#else
|
|
|
|
|
|
* AVR with 2-byte ISR Vectors and rjmp
|
|
* AVR with 2-byte ISR Vectors and rjmp
|
|
*/
|
|
*/
|
|
- if ((uint16_t)(void*)address == rstVect0) {
|
|
+ if (address.word == rstVect0) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- rstVect0_sav = buff[rstVect0];
|
|
+ rstVect0_sav = buff.bptr[rstVect0];
|
|
- rstVect1_sav = buff[rstVect1];
|
|
+ rstVect1_sav = buff.bptr[rstVect1];
|
|
- saveVect0_sav = buff[saveVect0];
|
|
+ saveVect0_sav = buff.bptr[saveVect0];
|
|
- saveVect1_sav = buff[saveVect1];
|
|
+ saveVect1_sav = buff.bptr[saveVect1];
|
|
|
|
|
|
|
|
|
|
- uint16_t vect=(rstVect0_sav & 0xff) | ((rstVect1_sav & 0x0f)<<8);
|
|
+
|
|
- vect = (vect-save_vect_num) & 0x0fff;
|
|
+
|
|
|
|
+ addr16_t vect;
|
|
|
|
+ vect.bytes[0] = rstVect0_sav;
|
|
|
|
+ vect.bytes[1] = rstVect1_sav;
|
|
|
|
+ vect.word = (vect.word-save_vect_num);
|
|
|
|
|
|
- buff[saveVect0] = vect & 0xff;
|
|
+ buff.bptr[saveVect0] = vect.bytes[0];
|
|
- buff[saveVect1] = (vect >> 8) | 0xc0;
|
|
+ buff.bptr[saveVect1] = (vect.bytes[1] & 0x0F)| 0xC0;
|
|
|
|
|
|
- vect = ((uint16_t)main) &0x0fff;
|
|
+ vect.word = ((uint16_t)main);
|
|
- buff[0] = vect & 0xFF;
|
|
+ buff.bptr[0] = vect.bytes[0];
|
|
- buff[1] = (vect >> 8) | 0xC0;
|
|
+ buff.bptr[1] = vect.bytes[1] | 0xC0;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
#endif
|
|
#endif
|
|
@@ -883,14 +944,14 @@ void appStart(uint8_t rstFlags) {
|
|
|
|
|
|
* void writebuffer(memtype, buffer, address, length)
|
|
* void writebuffer(memtype, buffer, address, length)
|
|
*/
|
|
*/
|
|
-static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
|
|
+static inline void writebuffer(int8_t memtype, addr16_t mybuff,
|
|
- uint16_t address, pagelen_t len)
|
|
+ addr16_t address, pagelen_t len)
|
|
{
|
|
{
|
|
switch (memtype) {
|
|
switch (memtype) {
|
|
case 'E':
|
|
case 'E':
|
|
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
|
|
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
|
|
while(len--) {
|
|
while(len--) {
|
|
- eeprom_write_byte((uint8_t *)(address++), *mybuff++);
|
|
+ eeprom_write_byte((address.bptr++), *(mybuff.bptr++));
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
|
|
|
|
@@ -910,8 +971,7 @@ static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
|
|
*/
|
|
*/
|
|
{
|
|
{
|
|
|
|
|
|
- uint8_t *bufPtr = mybuff;
|
|
+ uint16_t addrPtr = address.word;
|
|
- uint16_t addrPtr = (uint16_t)(void*)address;
|
|
|
|
|
|
|
|
|
|
|
|
* Start the page erase and wait for it to finish. There
|
|
* Start the page erase and wait for it to finish. There
|
|
@@ -919,24 +979,21 @@ static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
|
|
* the serial link, but the performance improvement was slight,
|
|
* the serial link, but the performance improvement was slight,
|
|
* and we needed the space back.
|
|
* and we needed the space back.
|
|
*/
|
|
*/
|
|
- __boot_page_erase_short((uint16_t)(void*)address);
|
|
+ __boot_page_erase_short(address.word);
|
|
boot_spm_busy_wait();
|
|
boot_spm_busy_wait();
|
|
|
|
|
|
|
|
|
|
* Copy data from the buffer into the flash write buffer.
|
|
* Copy data from the buffer into the flash write buffer.
|
|
*/
|
|
*/
|
|
do {
|
|
do {
|
|
- uint16_t a;
|
|
+ __boot_page_fill_short((uint16_t)(void*)addrPtr, *(mybuff.wptr++));
|
|
- a = *bufPtr++;
|
|
|
|
- a |= (*bufPtr++) << 8;
|
|
|
|
- __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
|
|
|
|
addrPtr += 2;
|
|
addrPtr += 2;
|
|
} while (len -= 2);
|
|
} while (len -= 2);
|
|
|
|
|
|
|
|
|
|
* Actually Write the buffer to flash (and wait for it to finish.)
|
|
* Actually Write the buffer to flash (and wait for it to finish.)
|
|
*/
|
|
*/
|
|
- __boot_page_write_short((uint16_t)(void*)address);
|
|
+ __boot_page_write_short(address.word);
|
|
boot_spm_busy_wait();
|
|
boot_spm_busy_wait();
|
|
#if defined(RWWSRE)
|
|
#if defined(RWWSRE)
|
|
|
|
|
|
@@ -947,7 +1004,7 @@ static inline void writebuffer(int8_t memtype, uint8_t *mybuff,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
|
|
+static inline void read_mem(uint8_t memtype, addr16_t address, pagelen_t length)
|
|
{
|
|
{
|
|
uint8_t ch;
|
|
uint8_t ch;
|
|
|
|
|
|
@@ -956,7 +1013,7 @@ static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
|
|
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
|
|
#if defined(SUPPORT_EEPROM) || defined(BIGBOOT)
|
|
case 'E':
|
|
case 'E':
|
|
do {
|
|
do {
|
|
- putch(eeprom_read_byte((uint8_t *)(address++)));
|
|
+ putch(eeprom_read_byte((address.bptr++)));
|
|
} while (--length);
|
|
} while (--length);
|
|
break;
|
|
break;
|
|
#endif
|
|
#endif
|
|
@@ -964,22 +1021,22 @@ static inline void read_mem(uint8_t memtype, uint16_t address, pagelen_t length)
|
|
do {
|
|
do {
|
|
#ifdef VIRTUAL_BOOT_PARTITION
|
|
#ifdef VIRTUAL_BOOT_PARTITION
|
|
|
|
|
|
- if (address == rstVect0) ch = rstVect0_sav;
|
|
+ if (address.word == rstVect0) ch = rstVect0_sav;
|
|
- else if (address == rstVect1) ch = rstVect1_sav;
|
|
+ else if (address.word == rstVect1) ch = rstVect1_sav;
|
|
- else if (address == saveVect0) ch = saveVect0_sav;
|
|
+ else if (address.word == saveVect0) ch = saveVect0_sav;
|
|
- else if (address == saveVect1) ch = saveVect1_sav;
|
|
+ else if (address.word == saveVect1) ch = saveVect1_sav;
|
|
- else ch = pgm_read_byte_near(address);
|
|
+ else ch = pgm_read_byte_near(address.bptr);
|
|
- address++;
|
|
+ address.bptr++;
|
|
#elif defined(RAMPZ)
|
|
#elif defined(RAMPZ)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- __asm__ ("elpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
|
|
+ __asm__ ("elpm %0,Z+\n" : "=r" (ch), "=z" (address.bptr): "1" (address));
|
|
#else
|
|
#else
|
|
|
|
|
|
- __asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address): "1" (address));
|
|
+ __asm__ ("lpm %0,Z+\n" : "=r" (ch), "=z" (address.bptr): "1" (address));
|
|
#endif
|
|
#endif
|
|
putch(ch);
|
|
putch(ch);
|
|
} while (--length);
|
|
} while (--length);
|