introduce new feature: BOOTLOADERENTRY_FROMSOFTWARE
authorStephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
Tue, 10 Sep 2013 13:35:11 +0000 (15:35 +0200)
committerStephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
Tue, 10 Sep 2013 13:57:01 +0000 (13:57 +0000)
An USBaspLoader supporting this feature is able to be called
(and bootLoaderConditioned) from user firmware.
You can check MCUCSR watchdog-flag to check for success.
(If USBaspLoader starts up, all MCUCSR are removed...)

You can use something like this code to switch to the
bootloader:

  #define BOOTLOADER_WORDADDRESS (BOOTLOADER_ADDRESS>>1)
  wdt_enable(WDTO_15MS);
  asm volatile (
    "ldi r29 , %[ramendhi] \n\t"
    "ldi r28 , %[ramendlo] \n\t"
    "ldi r16 , %[boothi] \n\t"
    "st Y+ , r16 \n\t"
    "ldi r16 , %[bootme] \n\t"
    "st Y+ , r16 \n\t"
    "ldi r16 , %[bootlo] \n\t"
    "st Y+ , r16 \n\t"
    "resetloop%=: \n\t"
    "rjmp resetloop%= \n\t"
    :
    : [ramendhi] "M" (((RAMEND - 2) >> 8) & 0xff),
      [ramendlo] "M" (((RAMEND - 2) >> 0) & 0xff),
      [boothi] "M" (((BOOTLOADER_WORDADDRESS) >>16) & 0xff),
      [bootme] "M" (((BOOTLOADER_WORDADDRESS) >> 8) & 0xff),
      [bootlo] "M" (((BOOTLOADER_WORDADDRESS) >> 0) & 0xff)
  );

Signed-off-by: Stephan Baerwolf <stephan.baerwolf@tu-ilmenau.de>
firmware/bootloaderconfig.h
firmware/main.c

index 531ba97..9ca2cd1 100644 (file)
@@ -312,6 +312,16 @@ these macros are defined, the boot loader usees them.
  * (except registers and IO), since RESET will NOT clear old RAM content.
  */
 
  * (except registers and IO), since RESET will NOT clear old RAM content.
  */
 
+#ifdef CONFIG_NO__BOOTLOADERENTRY_FROMSOFTWARE
+#      define HAVE_BOOTLOADERENTRY_FROMSOFTWARE 0
+#else
+#      define HAVE_BOOTLOADERENTRY_FROMSOFTWARE 1
+#endif
+/* 
+ * Enable firmware to boot the bootloader without
+ * user intervention
+ */
+
 //#define SIGNATURE_BYTES             0x1e, 0x93, 0x07, 0     /* ATMega8 */
 /* This macro defines the signature bytes returned by the emulated USBasp to
  * the programmer software. They should match the actual device at least in
 //#define SIGNATURE_BYTES             0x1e, 0x93, 0x07, 0     /* ATMega8 */
 /* This macro defines the signature bytes returned by the emulated USBasp to
  * the programmer software. They should match the actual device at least in
@@ -357,7 +367,41 @@ static inline void  bootLoaderExit(void)
     PIN_PORT(JUMPER_PORT) = 0;         /* undo bootLoaderInit() changes */
 }
 
     PIN_PORT(JUMPER_PORT) = 0;         /* undo bootLoaderInit() changes */
 }
 
-#define bootLoaderCondition()          ((PIN_PIN(JUMPER_PORT) & (1 << PIN(JUMPER_PORT, JUMPER_BIT))) == 0)
+
+#define bootLoaderConditionSimple()    ((PIN_PIN(JUMPER_PORT) & (1 << PIN(JUMPER_PORT, JUMPER_BIT))) == 0)
+
+#if (HAVE_BOOTLOADERENTRY_FROMSOFTWARE)
+/*
+ * How it works: The idea
+ * 
+ * During normal C initialization, the stackpointer (SP) always is pointed to
+ * SRAMs end, where it grows towards RAMSTART.
+ * 
+ * Check if last possible pushed address in stack is bootloaders address. 
+ * Store investigation result into "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch"
+ * Result will be "0xff" in case of mismatch.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define __BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS        (BOOTLOADER_ADDRESS>>1)
+static volatile uint8_t __BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch __attribute__ ((section(".noinit")));
+static volatile uint8_t __BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR __attribute__ ((section(".noinit")));
+
+static inline bool bootLoaderCondition(void)
+{
+  if (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR & (_BV(WDRF))) {
+    if (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch == (__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS & 0xff)) {
+      // anything else: match - the firmware is calling the bootloader
+      return true;
+    }
+  }
+  return bootLoaderConditionSimple();
+}
+#else
+#define bootLoaderCondition            bootLoaderConditionSimple
+#endif
 
 #endif /* __ASSEMBLER__ */
 
 
 #endif /* __ASSEMBLER__ */
 
index 19c7756..99bbb20 100644 (file)
@@ -196,6 +196,44 @@ static const uchar  signatureBytes[4] = {
 
 /* ------------------------------------------------------------------------ */
 
 
 /* ------------------------------------------------------------------------ */
 
+#if (HAVE_BOOTLOADERENTRY_FROMSOFTWARE)
+void __attribute__ ((section(".init3"),naked,used,no_instrument_function)) __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void);
+void __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND(void) {
+  asm volatile (
+    "in                %[mcucsrval]    ,       %[mcucsrio]\n\t"
+    "ldi       r29             ,       %[ramendhi]\n\t"
+    "ldi       r28             ,       %[ramendlo]\n\t"
+#if (FLASHEND>131071)
+    "ld                %[result]       ,       Y+\n\t"
+    "cpi       %[result]       ,       %[bootaddrhi]\n\t"
+    "brne      __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=\n\t"
+#endif
+    "ld                %[result]       ,       Y+\n\t"
+    "cpi       %[result]       ,       %[bootaddrme]\n\t"
+    "ld                %[result]       ,       Y+\n\t"
+    "breq      __BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=\n\t"
+
+    "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_mismatch%=:\n\t"
+    "ldi       %[result]       ,       0xff\n\t"
+
+    "__BOOTLOADERENTRY_FROMSOFTWARE__bootup_investigate_RAMEND_done%=:\n\t"
+    : [result]         "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_RAMEND_doesmatch),
+      [mcucsrval]      "=a" (__BOOTLOADERENTRY_FROMSOFTWARE__bootup_MCUCSR)
+    : [mcucsrio]       "I"  (_SFR_IO_ADDR(MCUCSR)),
+#if (FLASHEND>131071)
+      [ramendhi]       "M" (((RAMEND - 2) >> 8) & 0xff),
+      [ramendlo]       "M" (((RAMEND - 2) >> 0) & 0xff),
+      [bootaddrhi]     "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS) >>16) & 0xff),
+#else
+      [ramendhi]       "M" (((RAMEND - 1) >> 8) & 0xff),
+      [ramendlo]       "M" (((RAMEND - 1) >> 0) & 0xff),
+#endif
+      [bootaddrme]     "M" (((__BOOTLOADERENTRY_FROMSOFTWARE__EXPECTEDADDRESS) >> 8) & 0xff)
+    
+  );
+}
+#endif
+
 #if (USE_BOOTUP_CLEARRAM)
 /*
 * Under normal circumstances, RESET will not clear contents of RAM.
 #if (USE_BOOTUP_CLEARRAM)
 /*
 * Under normal circumstances, RESET will not clear contents of RAM.
@@ -206,8 +244,10 @@ void __func_clearram(void) {
   extern size_t __bss_end;
   asm volatile (
     "__clearram:\n\t"
   extern size_t __bss_end;
   asm volatile (
     "__clearram:\n\t"
+#if (!(HAVE_BOOTLOADERENTRY_FROMSOFTWARE))
     "ldi r29, %[ramendhi]\n\t"
     "ldi r28, %[ramendlo]\n\t"
     "ldi r29, %[ramendhi]\n\t"
     "ldi r28, %[ramendlo]\n\t"
+#endif
     "__clearramloop%=:\n\t"
     "st -Y , __zero_reg__\n\t"
     "cp r28, %A[bssend]\n\t"
     "__clearramloop%=:\n\t"
     "st -Y , __zero_reg__\n\t"
     "cp r28, %A[bssend]\n\t"
@@ -692,11 +732,11 @@ asm  volatile  (
 );
 #else
        if (stayinloader >= 0x10) {
 );
 #else
        if (stayinloader >= 0x10) {
-         if (!bootLoaderCondition()) {
+         if (!bootLoaderConditionSimple()) {
            stayinloader-=0x10;
          } 
        } else {
            stayinloader-=0x10;
          } 
        } else {
-         if (bootLoaderCondition()) {
+         if (bootLoaderConditionSimple()) {
            if (stayinloader > 1) stayinloader-=2;
          }
        }
            if (stayinloader > 1) stayinloader-=2;
          }
        }