From ece522dd49b016d16cf14f736b1682c3cc08c9a1 Mon Sep 17 00:00:00 2001 From: stephenf7072 <57785167+stephenf7072@users.noreply.github.com> Date: Fri, 24 Jul 2020 09:36:28 +1000 Subject: [PATCH 1/2] Removed code using non-core library (ie. Epoch stuff) I hate to undo even a little bit of Adam's good work, but in the interests of a robust core, I think it's best the references to time.h are removed, and the Epoch set/get along with it. RTC.cpp included , which caused a compilation error when these are also included in code: #include #include Some possible issues with Window lack of case sensitivity, refer here: https://forum.arduino.cc/index.php?topic=451360.0 Also with time.h (or Time.h?) being an optional extra install library to the Arduino IDE, best to leave it out of the core, especially if it can cause compilation errors. --- .../Example4_Set_Epoch/Example4_Set_Epoch.ino | 41 ------------------- libraries/RTC/keywords.txt | 2 - libraries/RTC/src/RTC.cpp | 41 ------------------- libraries/RTC/src/RTC.h | 2 - 4 files changed, 86 deletions(-) delete mode 100644 libraries/RTC/examples/Example4_Set_Epoch/Example4_Set_Epoch.ino diff --git a/libraries/RTC/examples/Example4_Set_Epoch/Example4_Set_Epoch.ino b/libraries/RTC/examples/Example4_Set_Epoch/Example4_Set_Epoch.ino deleted file mode 100644 index 04dd33d..0000000 --- a/libraries/RTC/examples/Example4_Set_Epoch/Example4_Set_Epoch.ino +++ /dev/null @@ -1,41 +0,0 @@ -/* - Author: Adam Garbo and Nathan Seidle - Created: June 3rd, 2020 - License: MIT. See SparkFun Arduino Apollo3 Project for more information - - This example demonstrates how to set the RTC using UNIX Epoch time. -*/ - -#include "RTC.h" // Include RTC library included with the Aruino_Apollo3 core -APM3_RTC myRTC; // Create instance of RTC class - -void setup() -{ - Serial.begin(115200); - Serial.println("SparkFun RTC Set UNIX Epoch Time Example"); - - // Set the RTC time using UNIX Epoch time - myRTC.setEpoch(1591185600); // E.g. 12:00:00, June 3rd, 2020 -} - -void loop() -{ - // Print UNIX Epoch timestamp - Serial.print("Epoch time: "); Serial.println(myRTC.getEpoch()); - - // Print RTC's date and time - Serial.print("Timestamp: "); printDateTime(); - - delay(1000); -} - -// Print the RTC's current date and time -void printDateTime() -{ - myRTC.getTime(); - char dateTime[20]; - sprintf(dateTime, "20%02d-%02d-%02d %02d:%02d:%02d", - myRTC.year, myRTC.month, myRTC.dayOfMonth, - myRTC.hour, myRTC.minute, myRTC.seconds); - Serial.println(dateTime); -} diff --git a/libraries/RTC/keywords.txt b/libraries/RTC/keywords.txt index 6b719de..e6831ec 100644 --- a/libraries/RTC/keywords.txt +++ b/libraries/RTC/keywords.txt @@ -13,11 +13,9 @@ RTC KEYWORD1 ####################################### getTime KEYWORD2 -getEpoch KEYWORD2 setTime KEYWORD2 setTimeToCompiler KEYWORD2 -setEpoch KEYWORD2 getAlarm KEYWORD2 setAlarm KEYWORD2 diff --git a/libraries/RTC/src/RTC.cpp b/libraries/RTC/src/RTC.cpp index c15eec3..6ec16a5 100644 --- a/libraries/RTC/src/RTC.cpp +++ b/libraries/RTC/src/RTC.cpp @@ -3,7 +3,6 @@ */ #include "RTC.h" -#include am_hal_rtc_time_t hal_time; am_hal_rtc_time_t alm_time; @@ -89,28 +88,6 @@ void APM3_RTC::setToCompilerTime() getTime(); } -void APM3_RTC::setEpoch(uint32_t ts) -{ - if (ts < EPOCH_TIME) { - ts = EPOCH_TIME; - } - - struct tm tm; - - time_t t = ts; - struct tm* tmp = gmtime(&t); - hal_time.ui32Weekday = 0; - hal_time.ui32Century = 0; - hal_time.ui32Year = tmp->tm_year - 100; - hal_time.ui32Month = tmp->tm_mon + 1; - hal_time.ui32DayOfMonth = tmp->tm_mday; - hal_time.ui32Hour = tmp->tm_hour; - hal_time.ui32Minute = tmp->tm_min; - hal_time.ui32Second = tmp->tm_sec; - hal_time.ui32Hundredths = 0; - - am_hal_rtc_time_set(&hal_time); //Initialize the RTC with this date/time -} void APM3_RTC::getTime() { @@ -127,24 +104,6 @@ void APM3_RTC::getTime() hundredths = hal_time.ui32Hundredths; } -uint32_t APM3_RTC::getEpoch() -{ - am_hal_rtc_time_get(&hal_time); - - struct tm tm; - - tm.tm_isdst = -1; - tm.tm_yday = 0; - tm.tm_wday = 0; - tm.tm_year = hal_time.ui32Year + 100; //Number of years since 1900. - tm.tm_mon = hal_time.ui32Month - 1; //mktime is expecting 0 to 11 months - tm.tm_mday = hal_time.ui32DayOfMonth; - tm.tm_hour = hal_time.ui32Hour; - tm.tm_min = hal_time.ui32Minute; - tm.tm_sec = hal_time.ui32Second; - - return mktime(&tm); -} void APM3_RTC::getAlarm() { diff --git a/libraries/RTC/src/RTC.h b/libraries/RTC/src/RTC.h index 93cede3..f52cbee 100644 --- a/libraries/RTC/src/RTC.h +++ b/libraries/RTC/src/RTC.h @@ -9,12 +9,10 @@ class APM3_RTC APM3_RTC(); void getTime(); //Query the RTC for the current time/date - uint32_t getEpoch(); //Return the current RTC time/date as UNIX Epoch time void setTime(uint8_t hour, uint8_t min, uint8_t sec, uint8_t hund, uint8_t dayOfMonth, uint8_t month, uint16_t year); //Set current time to provided hundredths/seconds/etc void setToCompilerTime(); //Set to time when sketch was compiled - void setEpoch(uint32_t ts); //Set current time to provided UNIX Epoch time void getAlarm(); //Query the RTC for the current alarm time/date void setAlarm(uint8_t hour, uint8_t min, uint8_t sec, uint8_t hund, uint8_t dayOfMonth, uint8_t month); //Set alarm time to provided hundredths/seconds/etc From 847eb3d6dd3ee33e2b3ea506d95056bf23d64dc8 Mon Sep 17 00:00:00 2001 From: stephenf7072 <57785167+stephenf7072@users.noreply.github.com> Date: Fri, 24 Jul 2020 11:32:07 +1000 Subject: [PATCH 2/2] Create Example8_ResetsAndWatchdog.ino --- .../Example8_ResetsAndWatchdog.ino | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 libraries/Examples/examples/Example8_ResetsAndWatchdog/Example8_ResetsAndWatchdog.ino diff --git a/libraries/Examples/examples/Example8_ResetsAndWatchdog/Example8_ResetsAndWatchdog.ino b/libraries/Examples/examples/Example8_ResetsAndWatchdog/Example8_ResetsAndWatchdog.ino new file mode 100644 index 0000000..81a1e0d --- /dev/null +++ b/libraries/Examples/examples/Example8_ResetsAndWatchdog/Example8_ResetsAndWatchdog.ino @@ -0,0 +1,196 @@ +/* Author: Stephen Fordyce (adapted from WDT example code by Adam Garbo - https://forum.sparkfun.com/viewtopic.php?f=169&t=52431&p=213296&hilit=watchdog#p213296) + Created: 24th July 2020 + License: MIT. See SparkFun Arduino Apollo3 Project for more information + + This example demonstrates use of the watchdog timer, also different ways of resetting the Artemis as well as how to determine the last reset type +*/ + +// Global variables +volatile uint8_t watchdogCounter = 0; // Watchdog interrupt counter +uint32_t resetStatus = 0; // Reset status register +bool testWatchdogResetFlag = false; +bool watchdogInterruptCallsEmergencyReset = false; +bool resetWDTEveryLoop = true; + +// Watchdog timer configuration structure. +am_hal_wdt_config_t g_sWatchdogConfig = { + //Substitude other values for AM_HAL_WDT_LFRC_CLK_16HZ to increase/decrease the range + .ui32Config = AM_HAL_WDT_LFRC_CLK_16HZ | AM_HAL_WDT_ENABLE_RESET | AM_HAL_WDT_ENABLE_INTERRUPT, // Configuration values for generated watchdog timer event. + //****** EVEN THOUGH THESE IMPLY 16-BIT, THEY ARE ONLY 8-BIT - 255 MAX! + .ui16InterruptCount = 120, //MAX 255! // Set WDT interrupt timeout for 5 seconds (120 / 16 = 8). // Number of watchdog timer ticks allowed before a watchdog interrupt event is generated. + .ui16ResetCount = 160 //MAX 255! // Set WDT reset timeout for 15 seconds (160 / 16 = 10). // Number of watchdog timer ticks allowed before the watchdog will issue a system reset. +}; + +void setup(void) +{ + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(115200); delay(10); + Serial.println();Serial.println(); + Serial.println("****Artemis Reset & Watchdog Reset Example****"); + + printResetReason(); //Explain reason for reset + am_hal_reset_control(AM_HAL_RESET_CONTROL_STATUSCLEAR, 0); // Clear reset status register for next time we reset. + delay(1000); + + startWatchdogTimer(); //Initialise and start the watchdog timer, in case the program gets stuck in a while loop or waiting for user input + printWatchdogDetails(); + delay(2000); + + Serial.println("\nRunning a time-consuming loop with watchdog running"); + for(int i=0; i<5; i++) + { + delay(1000); //Phew, a bunch of hard processing + printWatchdogValue(); + } + Serial.println("Yikes, the time kept increasing, even though we were doing legitimate work\n"); + + Serial.println("\nRunning a time-consuming loop that restarts the watchdog timer each loop"); + for(int i=0; i<5; i++) + { + delay(1000); //Phew, a bunch of hard processing + printWatchdogValue(); + am_hal_wdt_restart(); // "Pet" the dog. // Restart the watchdog. + } + Serial.println("Plenty of time, but the watchdog timer will still catch a freeze\n"); + delay(2000); +} + +void loop(void) +{ + Serial.println("Start of loop()"); + if(resetWDTEveryLoop) + am_hal_wdt_restart(); // "Pet" the dog. // Restart the watchdog. (every loop run seems good) + + if(resetWDTEveryLoop) + { + Serial.println("Enter 'r' to do a scheduled software reset"); + Serial.println("Enter 's' to stop resetting the watchdog timer each loop"); + delay(1000); + char option = Serial.read(); + if(option == 'r') + myScheduledReset(); + if(option == 's') + { + Serial.println("I take no responsibility for the consequences!"); + Serial.println("(the watchdog interrupt routine when triggered will reset the timer 3 times, watch the timer values to see when it's reset by the ISR)"); + delay(2000); + resetWDTEveryLoop = false; + } + } + + if(resetWDTEveryLoop == false) + { + Serial.println("Enter 'e' to let the watchdog interrupt call emergencyReset()"); + delay(1000); + char option = Serial.read(); + if(option == 'e') + { + Serial.println("Cool, that'll happen in a sec"); delay(20); + watchdogInterruptCallsEmergencyReset = true; + } + } + + if(testWatchdogResetFlag) + { + Serial.println("Just about to go down the rabbit hole..."); + delay(20); //Let serial buffer clear + while(1); //Intentionally get stuck, and hope that the watchdog timer saves the day + } + + printWatchdogValue(); + Serial.println(); + delay(10); + + //Optional code for sleeping - just halt the WDT before you disable everything, then re-initialise the WDT after waking up. Tested elsewhere, and does not have any appreciable impact on sleep currents or performance + //am_hal_wdt_halt(); + //sleepForABit(); + //startWatchdog(); +} + +// Interrupt handler for the watchdog. +extern "C" void am_watchdog_isr(void) +{ + am_hal_wdt_int_clear(); // Clear the watchdog interrupt. + if(watchdogInterruptCallsEmergencyReset) + emergencyReset(); + + if ( watchdogCounter < 3 ) // Catch the first three watchdog interrupts, but let the fourth through untouched. + { + digitalWrite(LED_BUILTIN, LOW); + am_hal_wdt_restart(); // "Pet" the dog (reset the timer) + } + else + { + digitalWrite(LED_BUILTIN, HIGH); // Indicator that a reset will occur. + testWatchdogResetFlag = true; + } + + watchdogCounter++; // Increment the number of watchdog interrupts. +} + +void startWatchdogTimer() +{ + am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_LFRC_START, 0); // LFRC must be turned on for this example as the watchdog only runs off of the LFRC. + am_hal_wdt_init(&g_sWatchdogConfig); // Configure the watchdog. + NVIC_EnableIRQ(WDT_IRQn); // Enable the interrupt for the watchdog in the NVIC. + am_hal_interrupt_master_enable(); + am_hal_wdt_start(); // Enable the watchdog. +} + +//IMPORTANT: IF THIS IS CALLED BY THE WATCHDOG TIMER INTERRUPT ROUTINE, IT NEEDS TO BE QUICK (NO PRINTING TO SERIAL OR DELAYS) +void emergencyReset() +{ + //Optional: write some bits to flash/EEPROM to help with recovery + + am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI,0); //Reset with option "Software Power On Initialization" SWPOI +// am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOR,0); //Reset with option SWPOR (same as SWPOI but different am_hal_reset_status bit) +} + +void myScheduledReset() +{ + //Optional: write some bits to flash/EEPROM to help with recovery + +// am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI,0); //Reset with option "Software Power On Initialization" SWPOI + am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOR,0); //Reset with option SWPOR (same as SWPOI but different am_hal_reset_status bit) +} + +void printWatchdogDetails() +{ + Serial.print("Interrupt Count = "); Serial.print(g_sWatchdogConfig.ui16InterruptCount ); Serial.println(" ticks"); + Serial.print("Reset Count = "); Serial.print(g_sWatchdogConfig.ui16ResetCount); Serial.println(" ticks"); + + // Print out reset status register. + am_hal_reset_status_t sStatus; // (Note: See am_hal_reset.h for RESET status structure) + am_hal_reset_status_get(&sStatus); + resetStatus = sStatus.eStatus; + char rStatus[30]; + sprintf(rStatus, "Reset Status Register = 0x%x", resetStatus); // (Note: Watch Dog Timer reset = 0x40) + Serial.println(rStatus); +} + +void printWatchdogValue() +{ + Serial.print("Watchdog timer:"); + Serial.println(am_hal_wdt_counter_get()); +} + +void printResetReason() +{ + am_hal_reset_status_t resetResult; + uint32_t resultOk = am_hal_reset_status_get(&resetResult); + Serial.print("Reset reason: "); + if(resultOk == AM_HAL_STATUS_FAIL) Serial.println("Failed to get reset status"); + if(resetResult.bEXTStat) Serial.println("External reset"); + if(resetResult.bPORStat) Serial.println("Power-On reset"); + if(resetResult.bBODStat) Serial.println("Brown-Out reset"); + if(resetResult.bSWPORStat) Serial.println("SW Power-On reset or AIRCR reset - in this example, indicates reset by myScheduledReset()"); + if(resetResult.bSWPOIStat) Serial.println("SW Power On Initialization reset - in this example, indicates reset by emergencyReset()"); + if(resetResult.bDBGRStat) Serial.println("Debugger reset"); + if(resetResult.bWDTStat) Serial.println("Watch Dog Timer reset - nothing in the Watchdog Timer Interrupt routine got to restarting the Watchdog Timer"); + if(resetResult.bBOUnregStat) Serial.println("Unregulated Supply Brownout event"); + if(resetResult.bBOCOREStat) Serial.println("Core Regulator Brownout event"); + if(resetResult.bBOMEMStat) Serial.println("Memory Regulator Brownout event"); + if(resetResult.bBOBLEStat) Serial.println("BLE/Burst Regulator Brownout event"); +// am_hal_reset_control(AM_HAL_RESET_CONTROL_STATUSCLEAR, 0); // (do this in setup() Clear reset status register for next time we reset. + Serial.println(); +}