diff --git a/cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.h b/cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.h index 6e515f57..4bb78a8e 100644 --- a/cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.h +++ b/cores/arduino/am_sdk_ap3/mcu/apollo3/hal/am_hal_uart.h @@ -172,8 +172,8 @@ am_hal_uart_transfer_t; // Flow control #define AM_HAL_UART_FLOW_CTRL_NONE 0 -#define AM_HAL_UART_FLOW_CTRL_CTS_ONLY UART_CR_CTSEN_Msk -#define AM_HAL_UART_FLOW_CTRL_RTS_ONLY UART_CR_RTSEN_Msk +#define AM_HAL_UART_FLOW_CTRL_CTS_ONLY UART0_CR_CTSEN_Msk +#define AM_HAL_UART_FLOW_CTRL_RTS_ONLY UART0_CR_RTSEN_Msk #define AM_HAL_UART_FLOW_CTRL_RTS_CTS (UART0_CR_CTSEN_Msk | \ UART0_CR_RTSEN_Msk) // FIFO enable/disable. diff --git a/cores/arduino/ard_sup/uart/ap3_uart.cpp b/cores/arduino/ard_sup/uart/ap3_uart.cpp index 0724371a..2ba32cd5 100644 --- a/cores/arduino/ard_sup/uart/ap3_uart.cpp +++ b/cores/arduino/ard_sup/uart/ap3_uart.cpp @@ -296,6 +296,22 @@ ap3_err_t Uart::set_config(HardwareSerial_Config_e HWSconfig) retval = AP3_INVALID_ARG; break; } + + //Setup flow control + _config.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE; + if(_pinRTS != AP3_UART_PIN_UNUSED && _pinCTS != AP3_UART_PIN_UNUSED) + { + _config.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_RTS_CTS; + } + else if(_pinRTS != AP3_UART_PIN_UNUSED) + { + _config.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_RTS_ONLY; + } + else if(_pinCTS != AP3_UART_PIN_UNUSED) + { + _config.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_CTS_ONLY; + } + return retval; } @@ -375,7 +391,7 @@ ap3_err_t Uart::_begin(void) if (_pinRTS != AP3_UART_PIN_UNUSED) { - retval = ap3_uart_pad_funcsel(_instance, AP3_UART_TX, ap3_gpio_pin2pad(_pinRTS), &funcsel); + retval = ap3_uart_pad_funcsel(_instance, AP3_UART_RTS, ap3_gpio_pin2pad(_pinRTS), &funcsel); if (retval != AP3_OK) { return retval; @@ -391,7 +407,7 @@ ap3_err_t Uart::_begin(void) if (_pinCTS != AP3_UART_PIN_UNUSED) { - retval = ap3_uart_pad_funcsel(_instance, AP3_UART_RX, ap3_gpio_pin2pad(_pinCTS), &funcsel); + retval = ap3_uart_pad_funcsel(_instance, AP3_UART_CTS, ap3_gpio_pin2pad(_pinCTS), &funcsel); if (retval != AP3_OK) { return retval; diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 00000000..b4bd5ad9 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,39 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +enableBurstMode KEYWORD2 +disableBurstMode KEYWORD2 +getCpuFreqMHz KEYWORD2 + +getInternalTemp KEYWORD2 + +analogWriteResolution KEYWORD2 +analogWriteFrameWidth KEYWORD2 +analogWriteFrequency KEYWORD2 +servoWrite KEYWORD2 + +enableFastShift KEYWORD2 +fastShiftOut KEYWORD2 +fastShiftIn KEYWORD2 + +secs KEYWORD2 +systicks KEYWORD2 +sysoverflows KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Examples/examples/Example9_ResetsAndWatchdog/Example9_ResetsAndWatchdog.ino b/libraries/Examples/examples/Example9_ResetsAndWatchdog/Example9_ResetsAndWatchdog.ino new file mode 100644 index 00000000..81a1e0d5 --- /dev/null +++ b/libraries/Examples/examples/Example9_ResetsAndWatchdog/Example9_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(); +} diff --git a/libraries/WDT/examples/Example1_WDT_Basic/Example1_WDT_Basic.ino b/libraries/WDT/examples/Example1_WDT_Basic/Example1_WDT_Basic.ino new file mode 100644 index 00000000..7d9a7097 --- /dev/null +++ b/libraries/WDT/examples/Example1_WDT_Basic/Example1_WDT_Basic.ino @@ -0,0 +1,81 @@ +/* + Author: Adam Garbo + Created: August 1st, 2020 + License: MIT. See SparkFun Arduino Apollo3 Project for more information + + This example demonstrates a simple configuration of the Artemis Watchdog Timer. + + The code will configure the watchdog for both interrupt and reset generation, + and immediately start the watchdog timer. + + The watchdog ISR provided will 'pet' the watchdog four times. On the fifth + interrupt, the watchdog will not be pet, so the 'reset' action can occur. + On the sixth timeout event, the WDT will issue a system reset, and the + program will start over from the beginning. + + The watchdogCounter will show the number of ticks before the watchdog + reset occurs. + + This example is based on the Ambiq SDK 2.4.2 watchdog.c example. + + Tested with SparkFun Artemis Redboard. +*/ + +#include "WDT.h" + +APM3_WDT wdt; + +volatile bool watchdogFlag = false; // Watchdog Timer ISR flag +volatile int watchdogInterrupt = 0; // Watchdog interrupt counter +unsigned long currentMillis = 0, + previousMillis = 0; + +void setup() { + + Serial.begin(115200); + + Serial.println("Artemis Watchdog Timer Example"); + + // Start the watchdog + wdt.start(); +} + +void loop() +{ + // Check for watchdog interrupts + if (watchdogFlag) + { + // Calculate duration between watchdog interrupts + currentMillis = millis() - previousMillis; + previousMillis = millis(); + + Serial.print("Interrupt: "); Serial.print(watchdogInterrupt); + Serial.print(" Period: "); Serial.print(currentMillis); Serial.println(" ms "); + + if (watchdogInterrupt == 5) + { + Serial.println("Warning: Watchdog has triggered a system reset"); + } + } + watchdogFlag = false; // Clear watchdog flag + delay(1); +} + +// Interrupt handler for the watchdog +extern "C" void am_watchdog_isr(void) +{ + // Clear the watchdog interrupt + wdt.clear(); + + // Catch the first four watchdog interrupts, but let the fifth through untouched + if ( watchdogInterrupt < 4 ) + { + wdt.restart(); // "Pet" the dog + } + else { + digitalWrite(LED_BUILTIN, HIGH); // Visual indication of system reset trigger + } + + watchdogFlag = true; // Set watchdog flag + watchdogInterrupt++; // Increment watchdog interrupt counter +} diff --git a/libraries/WDT/examples/Example2_WDT_Config/Example2_WDT_Config.ino b/libraries/WDT/examples/Example2_WDT_Config/Example2_WDT_Config.ino new file mode 100644 index 00000000..67733276 --- /dev/null +++ b/libraries/WDT/examples/Example2_WDT_Config/Example2_WDT_Config.ino @@ -0,0 +1,110 @@ +/* + Author: Adam Garbo + Created: August 1st, 2020 + License: MIT. See SparkFun Arduino Apollo3 Project for more information + + This example demonstrates how to modify the configuration of the Artemis + Watchdog Timer (WDT). + + The watchdog timer is controlled by a clock divider, interrupt ticks and + reset ticks. To achieve desired watchdog timing, a simple calculation can be made: + + period = # ticks / clock divider frequency + + Examples: + 128 interrupt ticks / 128 Hz clock = 1 second + 64 interrupt ticks / 16 Hz clock = 4 seconds + 32 interrupt ticks / 1 Hz clock = 32 seconds + 16 interrupt ticks / 1/16 Hz clock = 256 seconds + + The following code will configure the watchdog for both interrupt and reset + generation, and immediately start the watchdog timer. + The watchdog ISR provided will 'pet' the watchdog four times. On the fifth + interrupt, the watchdog will not be pet, so the 'reset' action can occur. + On the sixth timeout event, the WDT will issue a system reset, and the + program will start over from the beginning. + + This example is based on the Ambiq SDK 2.4.2 watchdog.c example. + + Tested with SparkFun Artemis Redboard. +*/ + +#include "WDT.h" + +APM3_WDT wdt; + +volatile bool watchdogFlag = false; // Watchdog Timer ISR flag +volatile int watchdogInterrupt = 0; // Watchdog interrupt counter + +unsigned long currentMillis = 0, + previousMillis = 0; + +void setup() +{ + Serial.begin(115200); + + Serial.println("Artemis Watchdog Timer Example"); + + // Configure the watchdog + /* + Available watchdog timer clock dividers. + Users can choose either the clock definition (i.e. WDT_128HZ) or Apoll3 core enumeration (i.e. 1) + WDT_OFF = 0 = Low Power Mode. This setting disables the watch dog timer + WDT_128HZ = 1 = 128 Hz + WDT_16HZ = 2 = 16 Hz + WDT_1HZ = 3 = 1 Hz + WDT1_16HZ = 4 = 1/16th Hz + */ + // Set watchdog timer clock to 128 Hz + // Set watchdog interrupt to 1 seconds (128 ticks / 128 Hz = 1 second) + // Set watchdog reset ~2 seconds (255 ticks / 128 Hz = 1.99 seconds) + // Note: Ticks are limited to 255 (8-bit) + wdt.configure(WDT_128HZ, 128, 255); // Equivalent to: wdt.configure(1, 128, 255); + wdt.start(); // Start the watchdog +} + +void loop() +{ + // Check for watchdog interrupts + if (watchdogFlag) + { + // Calculate duration between watchdog interrupts + currentMillis = millis() - previousMillis; + previousMillis = millis(); + + Serial.print("Interrupt: "); Serial.print(watchdogInterrupt); + Serial.print(" Period: "); Serial.print(currentMillis); Serial.println(" ms"); + + // The watchdog configurations can also be set individually + wdt.setClock(WDT_16HZ); // Set watchdog timer clock to 16 Hz + wdt.setInterrupt(64); // Set watchdog interrupt to 4 second (64 ticks / 16 Hz = 4 seconds) + wdt.setReset(96); // Set watchdog reset to 8 seconds (96 ticks / 16 Hz = 8 seconds) + + if (watchdogInterrupt == 9) + { + Serial.println("Warning: Watchdog has triggered a system reset"); + } + } + watchdogFlag = false; // Clear watchdog flag + delay(1); +} + +// Interrupt handler for the watchdog +extern "C" void am_watchdog_isr(void) +{ + // Clear the watchdog interrupt + wdt.clear(); + + // Catch the first eight watchdog interrupts, but let the ninth through untouched + if ( watchdogInterrupt < 8 ) + { + wdt.restart(); // "Pet" the dog + } + else + { + digitalWrite(LED_BUILTIN, HIGH); // Visual indication of system reset trigger + } + + watchdogFlag = true; // Set watchdog flag + watchdogInterrupt++; // Increment watchdog interrupt counter +} diff --git a/libraries/WDT/examples/Example3_WDT_LowPower/Example3_WDT_LowPower.ino b/libraries/WDT/examples/Example3_WDT_LowPower/Example3_WDT_LowPower.ino new file mode 100644 index 00000000..26cd6902 --- /dev/null +++ b/libraries/WDT/examples/Example3_WDT_LowPower/Example3_WDT_LowPower.ino @@ -0,0 +1,168 @@ +/* + Author: Adam Garbo + Created: August 1st, 2020 + License: MIT. See SparkFun Arduino Apollo3 Project for more information + + This example demonstrates the combined use of the Artemis Watchdog Timer (WDT) + and real-time clock (RTC). + + Both RTC and WDT interrupts will wake the system, print the date and time, + and then re-enter deep sleep. + + The WDT is configured to trigger every 10 seconds. If the WDT is not "pet" + after 100 seconds, a system reset will be triggered. + + The RTC alarm is configured to trigger every minute and enter deep sleep + between interrupts. Alarm interuptswill also restart the WDT and reset + the watchdog interrput counter. +*/ + +#include "RTC.h" +#include "WDT.h" + +APM3_RTC rtc; +APM3_WDT wdt; + +volatile bool alarmFlag = false; // RTC ISR flag +volatile bool watchdogFlag = false; // Watchdog Timer ISR flag +volatile int watchdogInterrupt = 0; // Watchdog interrupt counter + +void setup() +{ + Serial.begin(115200); + + Serial.println("Artemis Watchdog Low Power Example"); + + // Set the RTC time using UNIX Epoch time + rtc.setEpoch(1596240000); // Saturday, August 1, 2020 00:00:00 + + // Set the RTC's alarm + rtc.setAlarm(0, 0, 0, 0, 0, 0); // Set alarm (hund, ss, mm, hh, dd, mm) + rtc.setAlarmMode(6); // Set the RTC alarm to trigger every minute + rtc.attachInterrupt(); // Attach RTC alarm interrupt + + // Configure the watchdog timer + // See Example2_WDT_Config for more information on how to configure the watchdog + wdt.configure(WDT_16HZ, 160, 240); // 16 Hz clock, 10-second interrupt period, 15-second reset period + + // Start the watchdog + wdt.start(); +} + +void loop() +{ + // Check for alarm interrupt + if (alarmFlag) + { + Serial.print("Alarm interrupt: "); + printDateTime(); // Print RTC's date and time + alarmFlag = false; + + wdt.restart(); // "Pet" the dog + watchdogInterrupt = 0; // Reset watchdog interrupt counter + } + + // Check for watchdog interrupt + if (watchdogFlag) + { + Serial.print("Watchdog interrupt: "); + printDateTime(); // Print RTC's date and time + watchdogFlag = false; // Clear watchdog flag + } + + goToSleep(); // Enter deep sleep +} + +// Print the RTC's current date and time +void printDateTime() +{ + rtc.getTime(); + Serial.printf("20%02d-%02d-%02d %02d:%02d:%02d.%02d\n", + rtc.year, rtc.month, rtc.dayOfMonth, + rtc.hour, rtc.minute, rtc.seconds, rtc.hundredths); +} + +// Power down gracefully +void goToSleep() +{ + // Disable UART + Serial.end(); + + // Disable ADC + power_adc_disable(); + + // Force the peripherals off + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM0); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM1); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM2); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM3); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM4); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_IOM5); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART0); + am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_UART1); + + // Disable all pads + for (int x = 0 ; x < 50 ; x++) + am_hal_gpio_pinconfig(x, g_AM_HAL_GPIO_DISABLE); + + //Power down Flash, SRAM, cache + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); // Turn off CACHE + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_512K); // Turn off everything but lower 512k + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_64K_DTCM); // Turn off everything but lower 64k + //am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_ALL); //Turn off all memory (doesn't recover) + + // Keep the 32kHz clock running for RTC + am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); + am_hal_stimer_config(AM_HAL_STIMER_XTAL_32KHZ); + + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); // Sleep forever + + // And we're back! + wakeUp(); +} + +// Power up gracefully +void wakeUp() +{ + // Power up SRAM, turn on entire Flash + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_MAX); + + // Go back to using the main clock + am_hal_stimer_config(AM_HAL_STIMER_CFG_CLEAR | AM_HAL_STIMER_CFG_FREEZE); + am_hal_stimer_config(AM_HAL_STIMER_HFRC_3MHZ); + + // Enable ADC + ap3_adc_setup(); + + // Enable Serial + Serial.begin(115200); +} + +// Interrupt handler for the RTC +extern "C" void am_rtc_isr(void) +{ + // Clear the RTC alarm interrupt + am_hal_rtc_int_clear(AM_HAL_RTC_INT_ALM); + + alarmFlag = true; // Set alarm flag +} + +// Interrupt handler for the watchdog. +extern "C" void am_watchdog_isr(void) +{ + // Clear the watchdog interrupt + wdt.clear(); + + // Perform system reset after 10 watchdog interrupts (should not occur) + if ( watchdogInterrupt < 10 ) + { + wdt.restart(); // "Pet" the dog + } + else { + digitalWrite(LED_BUILTIN, HIGH); // Visual indication of system reset trigger + } + + watchdogFlag = true; // Set the watchdog flag + watchdogInterrupt++; // Increment watchdog interrupt counter +} diff --git a/libraries/WDT/keywords.txt b/libraries/WDT/keywords.txt new file mode 100644 index 00000000..b84d6784 --- /dev/null +++ b/libraries/WDT/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WDT KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +configure KEYWORD2 +start KEYWORD2 +stop KEYWORD2 +restart KEYWORD2 +clear KEYWORD2 +getCounter KEYWORD2 +configure KEYWORD2 +setClock KEYWORD2 +setInterrupt KEYWORD2 +setReset KEYWORD2 +WDT_OFF KEYWORD2 +WDT_128HZ KEYWORD2 +WDT_16 KEYWORD2 +WDT_1HZ KEYWORD2 +WDT1_16HZ KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/WDT/library.properties b/libraries/WDT/library.properties new file mode 100644 index 00000000..bc7d8dab --- /dev/null +++ b/libraries/WDT/library.properties @@ -0,0 +1,9 @@ +name=WDT +version=0.1 +author=SparkFun Electronics +maintainer=SparkFun Electronics +sentence=Watchdog Timer (WDT) library for the SparkFun Artemis +paragraph=Enables the setting and reading of the internal Watchdog Timer built into Apollo based modules like the Artemis. +category= +url= +architectures=apollo3 diff --git a/libraries/WDT/src/WDT.cpp b/libraries/WDT/src/WDT.cpp new file mode 100644 index 00000000..3c11bcba --- /dev/null +++ b/libraries/WDT/src/WDT.cpp @@ -0,0 +1,94 @@ +#include "WDT.h" + +// Constructor +APM3_WDT::APM3_WDT() +{ + // The watchdog only runs off of the LFRC + am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_LFRC_START, 0); + am_hal_wdt_init(&watchdogConfig); +} + +// Configure the watchdog timer +// clock: set the LFRC clock frequency of the watchdog timer (see setClock below) +// interrupt: number of watchdog timer ticks allowed before a watchdog interrupt event is generated +// reset: number of watchdog timer ticks allowed before the watchdog will issue a system reset +void APM3_WDT::configure(uint8_t clock, uint8_t interrupt, uint8_t reset) +{ + if(clock <= 4) + { + WDT->CFG_b.CLKSEL = clock; + } + else + { + WDT->CFG_b.CLKSEL = WDT_CFG_CLKSEL_16HZ; // Default to 16Hz LFRC clock divider + } + WDT->CFG_b.INTVAL = interrupt; + WDT->CFG_b.RESVAL = reset; +} + +// Set the LFRC clock frequency of the watchdog timer +// WDT_OFF WDT_CFG_CLKSEL_OFF // = 0 Low Power Mode. This setting disables the watch dog timer +// WDT_128HZ WDT_CFG_CLKSEL_128HZ // = 1, 128 Hz LFRC clock +// WDT_16HZ WDT_CFG_CLKSEL_16HZ // = 2 16 Hz LFRC clock +// WDT_1HZ WDT_CFG_CLKSEL_1HZ // = 3, 1 Hz LFRC clock +// WDT_1_16HZ WDT_CFG_CLKSEL_1_16HZ // = 4, 1/16th Hz LFRC clock +void APM3_WDT::setClock(uint8_t clock) +{ + if(clock <= 4) + { + WDT->CFG_b.CLKSEL = clock; + } + else + { + WDT->CFG_b.CLKSEL = WDT_CFG_CLKSEL_16HZ; // Default to 16Hz LFRC clock divider + } +} + +// Set number of watchdog timer ticks allowed before a watchdog interrupt event is generated +void APM3_WDT::setInterrupt(uint8_t interrupt) +{ + WDT->CFG_b.INTVAL = interrupt; +} + +// Set number of watchdog timer ticks allowed before the watchdog will issue a system reset +void APM3_WDT::setReset(uint8_t reset) +{ + WDT->CFG_b.RESVAL = reset; +} + +// Enable the watchdog +void APM3_WDT::start() +{ + am_hal_interrupt_master_enable(); // Enable interrupts to the core + NVIC_EnableIRQ(WDT_IRQn); // Enable the interrupt for the watchdog in the NVIC + am_hal_wdt_start(); +} + +// Disable the watchdog +void APM3_WDT::stop() +{ + // Disable the interrupt for the watchdog in the NVIC + NVIC_DisableIRQ(WDT_IRQn); + // Disable the watchdog timer tick by clearing the 'enable' bit in the + // watchdog configuration register + am_hal_wdt_halt(); +} + +// Restart the watchdog +void APM3_WDT::restart() +{ + am_hal_wdt_restart(); +} + +// Clear the watchdog interrupt +void APM3_WDT::clear() +{ + am_hal_wdt_int_clear(); +} + +// Read the current value of watch dog timer counter register +uint32_t APM3_WDT::getCounter() +{ + return am_hal_wdt_counter_get(); +} + diff --git a/libraries/WDT/src/WDT.h b/libraries/WDT/src/WDT.h new file mode 100644 index 00000000..fc342146 --- /dev/null +++ b/libraries/WDT/src/WDT.h @@ -0,0 +1,41 @@ +#ifndef WDT_H +#define WDT_H + +#include + +// Simplified WDT Clock Divider Selections +#define WDT_OFF WDT_CFG_CLKSEL_OFF // = 0 Low Power Mode. This setting disables the watch dog timer +#define WDT_128HZ WDT_CFG_CLKSEL_128HZ // = 1, 128 Hz LFRC clock +#define WDT_16HZ WDT_CFG_CLKSEL_16HZ // = 2 16 Hz LFRC clock +#define WDT_1HZ WDT_CFG_CLKSEL_1HZ // = 3, 1 Hz LFRC clock +#define WDT_1_16HZ WDT_CFG_CLKSEL_1_16HZ // = 4, 1/16th Hz LFRC clock + +class APM3_WDT +{ +public: + APM3_WDT(); + + // Default watchdog timer configuration structure + am_hal_wdt_config_t watchdogConfig = { + + // Configuration values for generated watchdog timer event. + .ui32Config = AM_HAL_WDT_LFRC_CLK_16HZ | AM_HAL_WDT_ENABLE_RESET | AM_HAL_WDT_ENABLE_INTERRUPT, + + // Number of watchdog timer ticks allowed before a watchdog interrupt event is generated + .ui16InterruptCount = 16 * 4, // Set WDT interrupt timeout for 4 seconds (16 * 4) / 16 = 4 + + // Number of watchdog timer ticks allowed before the watchdog will issue a system reset + .ui16ResetCount = 16 * 8 // Set WDT reset timeout for 8 seconds (16 * 8 ) / 16 = 8 + }; + + void start(); // Starts the watchdog timer + void stop(); // Disables the watchdog timer + void restart(); // Restarts the watchdog timer ("Pets" the dog) + void clear(); // Clears the watchdog interrupt + uint32_t getCounter(); // Reads the current value of watch dog timer counter register + void configure(uint8_t clock, uint8_t interrupt, uint8_t reset); + void setClock(uint8_t clock); // Set the clock frequency of the watchdog timer + void setInterrupt(uint8_t interrupt); // Set number of ticks before a watchdog interrupt event is generated + void setReset(uint8_t reset); // Set number of ticks before the watchdog will issue a system reset +}; +#endif //WDT_H