Browse Source

More options for testing RESET/MCUSR behavior

WestfW 6 years ago
parent
commit
5803649901
1 changed files with 94 additions and 52 deletions
  1. 94 52
      optiboot/examples/test_reset/test_reset.ino

+ 94 - 52
optiboot/examples/test_reset/test_reset.ino

@@ -1,72 +1,73 @@
 /*
- * test_reset
- * May 2015 by Bill Westfield (WestfW)
- * Released to the public domain.
- *
- * This sketch demonstrates retrival of the Reset Cause register (MCUSR) of the AVR.
- * Normally, MCUSR itself is destroyed by the use of a bootloader, but Optiboot v4.6
- * and later save the contents in register r2, where it can be accessed by an
- * application.
- */
+   test_reset
+   May 2015 by Bill Westfield (WestfW)
+   Released to the public domain.
+
+   This sketch demonstrates retrival of the Reset Cause register (MCUSR) of the AVR.
+   Normally, MCUSR itself is destroyed by the use of a bootloader, but Optiboot v4.6
+   and later save the contents in register r2, where it can be accessed by an
+   application.
+*/
 #include <avr/wdt.h>
+#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)
+#include <LowPower.h>
+#endif
 
 /*
- * First, we need a variable to hold the reset cause that can be written before
- * early sketch initialization (that might change r2), and won't be reset by the
- * various initialization code.
- * avr-gcc provides for this via the ".noinit" section.
- */
+   First, we need a variable to hold the reset cause that can be written before
+   early sketch initialization (that might change r2), and won't be reset by the
+   various initialization code.
+   avr-gcc provides for this via the ".noinit" section.
+*/
 uint8_t resetFlag __attribute__ ((section(".noinit")));
 
 /*
- * Next, we need to put some code to save reset cause from the bootload (in r2)
- * to the variable.  Again, avr-gcc provides special code sections for this.
- * If compiled with link time optimization (-flto), as done by the Arduno
- * IDE version 1.6 and higher, we need the "used" attribute to prevent this
- * from being omitted.
- */
+   Next, we need to put some code to save reset cause from the bootload (in r2)
+   to the variable.  Again, avr-gcc provides special code sections for this.
+   If compiled with link time optimization (-flto), as done by the Arduno
+   IDE version 1.6 and higher, we need the "used" attribute to prevent this
+   from being omitted.
+*/
 void resetFlagsInit(void) __attribute__ ((naked))
-                          __attribute__ ((used))
-                          __attribute__ ((section (".init0")));
+__attribute__ ((used))
+__attribute__ ((section (".init0")));
 void resetFlagsInit(void)
 {
   /*
-   * save the reset flags passed from the bootloader
-   * This is a "simple" matter of storing (STS) r2 in the special variable
-   * that we have created.  We use assembler to access the right variable.
-   */
+     save the reset flags passed from the bootloader
+     This is a "simple" matter of storing (STS) r2 in the special variable
+     that we have created.  We use assembler to access the right variable.
+  */
   __asm__ __volatile__ ("sts %0, r2\n" : "=m" (resetFlag) :);
 }
 
 void printReset(const char *label, uint8_t resetFlags)
 {
-  
   Serial.print(label);
   Serial.print(resetFlags, HEX);
-  
   /*
-   * check for the usual bits.  Note that the symnbols defined in wdt.h are
-   * bit numbers, so they have to be shifted before comparison.
-   */
-  if (resetFlags & (1<<WDRF))
+     check for the usual bits.  Note that the symnbols defined in wdt.h are
+     bit numbers, so they have to be shifted before comparison.
+  */
+  if (resetFlags & (1 << WDRF))
   {
-    Serial.print(" Watchdog");
-    resetFlags &= ~(1<<WDRF);
+    Serial.print(F(" Watchdog"));
+    resetFlags &= ~(1 << WDRF);
   }
-  if (resetFlags & (1<<BORF))
+  if (resetFlags & (1 << BORF))
   {
-    Serial.print(" Brownout");
-    resetFlags &= ~(1<<BORF);
+    Serial.print(F(" Brownout"));
+    resetFlags &= ~(1 << BORF);
   }
-  if (resetFlags & (1<<EXTRF))
+  if (resetFlags & (1 << EXTRF))
   {
-    Serial.print(" External");
-    resetFlags &= ~(1<<EXTRF);
+    Serial.print(F(" External"));
+    resetFlags &= ~(1 << EXTRF);
   }
-  if (resetFlags & (1<<PORF))
+  if (resetFlags & (1 << PORF))
   {
-    Serial.print(" PowerOn");
-    resetFlags &= ~(1<<PORF);
+    Serial.print(F(" PowerOn"));
+    resetFlags &= ~(1 << PORF);
   }
   if (resetFlags != 0x00)
   {
@@ -76,20 +77,61 @@ void printReset(const char *label, uint8_t resetFlags)
   Serial.println("");
 }
 
-
 void setup() {
   Serial.begin(9600);  // Initialize serial port
-  
-  Serial.println("Reset flag test");
+
+  Serial.println(F("Reset flag test\n"));
+
   printReset("Actual MCUSR content: 0x", MCUSR);
-  printReset("Passed in GPIOR0: 0x", GPIOR0);
   printReset("Passed in R2: 0x", resetFlag);
+#ifdef GPIOR0
+  printReset("Passed in GPIOR0: 0x", GPIOR0);
+#endif
 }
-  
+
 void loop() {
-  Serial.println("Send something to reset through watchdog peripheral");
-  while (Serial.read() < 0) ;
-  wdt_enable(WDTO_15MS);
-  while (1); // To prevent the loop to start again before WDT resets the board
+  int ch;
+  Serial.println(F("\nSend 0-9 to set MCUSR, (W)atchdog enable, (J)mp to bootload, (S)leep"));
+  while ((ch = Serial.read()) < 0) ;
+  if (ch >= '0' && ch <= '9') {
+    MCUSR = ch & 0xF;
+    printReset("\nNew MCUSR content: 0x", MCUSR);
+  } else
+    switch (ch & ~('a' - 'A')) {
+      
+      case 'W':
+        wdt_enable(WDTO_15MS);
+        while (1); // To prevent the loop to start again before WDT resets the board
+        break;
+      case 'S':
+#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__)
+        // Enter power down state for 8 s with ADC and BOD module disabled
+        Serial.println(F("Low Power Sleep Mode"));
+        Serial.flush();
+        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
+        Serial.println(F("Sleep Wakeup"));
+        Serial.flush();
+#else
+        Serial.print(F("\nPower down not supported on this CPU\n"));
+#endif
+        break;
+        
+      case 'J':
+        /* Figure out where the bootloader starts. */
+#if FLASHEND > 140000
+        Serial.println(F("Jump to bootloader not supported on chips with >128k memory"));
+#else
+        typedef void (*do_reboot_t)(void);
+        const do_reboot_t do_reboot = (do_reboot_t)((FLASHEND - 511) >> 1);
+
+        Serial.print("bootstart = ");
+        Serial.println((unsigned int)do_reboot, HEX);
+        Serial.flush();
+        cli(); TCCR0A = TCCR1A = TCCR2A = 0; // make sure interrupts are off and timers are reset.
+        do_reboot();
+#endif
+        break;
+    }
+
 }