123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- 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.
- */
- 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.
- */
- void resetFlagsInit(void) __attribute__ ((naked))
- __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.
- */
- __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))
- {
- Serial.print(F(" Watchdog"));
- resetFlags &= ~(1 << WDRF);
- }
- if (resetFlags & (1 << BORF))
- {
- Serial.print(F(" Brownout"));
- resetFlags &= ~(1 << BORF);
- }
- if (resetFlags & (1 << EXTRF))
- {
- Serial.print(F(" External"));
- resetFlags &= ~(1 << EXTRF);
- }
- if (resetFlags & (1 << PORF))
- {
- Serial.print(F(" PowerOn"));
- resetFlags &= ~(1 << PORF);
- }
- if (resetFlags != 0x00)
- {
- // It should never enter here
- Serial.print(" Unknown");
- }
- Serial.println("");
- }
- void setup() {
- #if 1
- /*
- * if we're going to allow the bootloader to be called as a service ('j" command),
- * then we need to disable the WDT when the sketch starts. Essentially, there is no
- * way to tell a watchdog that occurs during the sketch from the watchdog that will
- * re-start the sketch when the bootloader is called from the application.
- */
- MCUSR = ~(1 << WDRF); // allow us to disable WD
- wdt_disable();
- #endif
- Serial.begin(9600); // Initialize serial port
- Serial.println(F("Reset flag test\n"));
- printReset("Actual MCUSR content: 0x", MCUSR);
- printReset("Passed in R2: 0x", resetFlag);
- #ifdef GPIOR0
- printReset("Passed in GPIOR0: 0x", GPIOR0);
- #endif
- }
- void loop() {
- 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;
- }
- }
|