Чуть правленные исходники v3.11 1.11: изменен делитель тактирования spi + частота кварца для мастер станции
This commit is contained in:
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#include "Adafruit_SleepyDog.h"
|
||||
|
||||
// Global instance of the main class for sketches to use.
|
||||
WatchdogType Watchdog;
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#ifndef ADAFRUIT_SLEEPYDOG_H
|
||||
#define ADAFRUIT_SLEEPYDOG_H
|
||||
|
||||
// Platform-specific code goes below. Each #ifdef should check for the presence
|
||||
// of their platform and pull in the appropriate watchdog implementation type,
|
||||
// then typedef it to WatchdogType so the .cpp file can create a global instance.
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(__AVR__)
|
||||
#include "utility/WatchdogAVR.h"
|
||||
typedef WatchdogAVR WatchdogType;
|
||||
#elif defined(ARDUINO_ARCH_SAMD)
|
||||
// Arduino Zero / ATSAMD series CPU watchdog support.
|
||||
#include "utility/WatchdogSAMD.h"
|
||||
typedef WatchdogSAMD WatchdogType;
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// Teensy 3.x watchdog support.
|
||||
#include "utility/WatchdogKinetisK.h"
|
||||
typedef WatchdogKinetisKseries WatchdogType;
|
||||
#elif defined(__MKL26Z64__)
|
||||
// Teensy LC watchdog support.
|
||||
#include "utility/WatchdogKinetisL.h"
|
||||
typedef WatchdogKinetisLseries WatchdogType;
|
||||
#else
|
||||
#error Unsupported platform for the Adafruit Watchdog library!
|
||||
#endif
|
||||
|
||||
extern WatchdogType Watchdog;
|
||||
|
||||
#endif
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Adafruit Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
# Adafruit SleepyDog Arduino Library
|
||||
|
||||
Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||
|
||||
Currently supports the following hardware:
|
||||
|
||||
* Arduino Uno or other ATmega328P-based boards.
|
||||
* Arduino Mega or other ATmega2560- or 1280-based boards.
|
||||
* Arduino Zero, Adafruit Feather M0 (ATSAMD21).
|
||||
* Arduino Leonardo or other 32u4-based boards (e.g. Adafruit Feather) WITH CAVEAT: USB Serial connection is clobbered on sleep; if sketch does not require Serial comms, this is not a concern. The example sketches all print to Serial and appear frozen, but the logic does otherwise continue to run. You can restore the USB serial connection after waking up using `USBDevice.attach();` and then reconnect to USB serial from the host machine.
|
||||
* Partial support for Teensy 3.X and LC (watchdog, no sleep).
|
||||
|
||||
Adafruit Trinket and other boards using ATtiny MCUs are NOT supported.
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// Adafruit Watchdog Library Basic Usage Example
|
||||
//
|
||||
// Simple example of how to use the watchdog library.
|
||||
//
|
||||
// Author: Tony DiCola
|
||||
|
||||
#include <Adafruit_SleepyDog.h>
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // wait for Arduino Serial Monitor (native USB boards)
|
||||
Serial.println("Adafruit Watchdog Library Demo!");
|
||||
Serial.println();
|
||||
|
||||
// First a normal example of using the watchdog timer.
|
||||
// Enable the watchdog by calling Watchdog.enable() as below.
|
||||
// This will turn on the watchdog timer with a ~4 second timeout
|
||||
// before reseting the Arduino. The estimated actual milliseconds
|
||||
// before reset (in milliseconds) is returned.
|
||||
// Make sure to reset the watchdog before the countdown expires or
|
||||
// the Arduino will reset!
|
||||
int countdownMS = Watchdog.enable(4000);
|
||||
Serial.print("Enabled the watchdog with max countdown of ");
|
||||
Serial.print(countdownMS, DEC);
|
||||
Serial.println(" milliseconds!");
|
||||
Serial.println();
|
||||
|
||||
// Now loop a few times and periodically reset the watchdog.
|
||||
Serial.println("Looping ten times while resetting the watchdog...");
|
||||
for(int i = 1; i <= 10; ++i) {
|
||||
Serial.print("Loop #"); Serial.println(i, DEC);
|
||||
delay(1000);
|
||||
// Reset watchdog with every loop to make sure the sketch keeps running.
|
||||
// If you comment out this call watch what happens in about 4 iterations!
|
||||
Watchdog.reset();
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
// Disable the watchdog entirely by calling Watchdog.disable();
|
||||
Watchdog.disable();
|
||||
|
||||
// Finally demonstrate the watchdog resetting by enabling it for a shorter
|
||||
// period of time and waiting a long time without a reset. Notice you can
|
||||
// pass a _maximum_ countdown time (in milliseconds) to the enable call.
|
||||
// The library will try to use that value as the countdown, but it might
|
||||
// pick a smaller value if the hardware doesn't support it. The actual
|
||||
// countdown value will be returned so you can see what it is.
|
||||
countdownMS = Watchdog.enable(4000);
|
||||
Serial.print("Get ready, the watchdog will reset in ");
|
||||
Serial.print(countdownMS, DEC);
|
||||
Serial.println(" milliseconds!");
|
||||
Serial.println();
|
||||
delay(countdownMS+1000);
|
||||
|
||||
// Execution will never get here because the watchdog resets the Arduino!
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// We'll never actually get to the loop because the watchdog will reset in
|
||||
// the setup function.
|
||||
Serial.println("You shouldn't see this message.");
|
||||
delay(1000);
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
// Adafruit Watchdog Library Sleep Example
|
||||
//
|
||||
// Simple example of how to do low power sleep with the watchdog timer.
|
||||
//
|
||||
// Author: Tony DiCola
|
||||
|
||||
#include <Adafruit_SleepyDog.h>
|
||||
|
||||
void setup() {
|
||||
// For boards with "native" USB support (e.g. not using an FTDI chip or
|
||||
// similar serial bridge), Serial connection may be lost on sleep/wake,
|
||||
// and you might not see the "I'm awake" messages. Use the onboard LED
|
||||
// as an alternate indicator -- the code turns it on when awake, off
|
||||
// before going to sleep.
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Show we're awake
|
||||
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // wait for Arduino Serial Monitor (native USB boards)
|
||||
Serial.println("Adafruit Watchdog Library Sleep Demo!");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("Going to sleep in one second...");
|
||||
delay(1000);
|
||||
|
||||
// To enter low power sleep mode call Watchdog.sleep() like below
|
||||
// and the watchdog will allow low power sleep for as long as possible.
|
||||
// The actual amount of time spent in sleep will be returned (in
|
||||
// milliseconds).
|
||||
digitalWrite(LED_BUILTIN, LOW); // Show we're asleep
|
||||
int sleepMS = Watchdog.sleep();
|
||||
|
||||
// Alternatively you can provide a millisecond value to specify
|
||||
// how long you'd like the chip to sleep, but the hardware only
|
||||
// supports a limited range of values so the actual sleep time might
|
||||
// be smaller. The time spent in sleep will be returned (in
|
||||
// milliseconds).
|
||||
// int sleepMS = Watchdog.sleep(1000); // Sleep for up to 1 second.
|
||||
|
||||
// Code resumes here on wake.
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Show we're awake again
|
||||
|
||||
// Try to reattach USB connection on "native USB" boards (connection is
|
||||
// lost on sleep). Host will also need to reattach to the Serial monitor.
|
||||
// Seems not entirely reliable, hence the LED indicator fallback.
|
||||
#ifdef USBCON
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
|
||||
Serial.print("I'm awake now! I slept for ");
|
||||
Serial.print(sleepMS, DEC);
|
||||
Serial.println(" milliseconds.");
|
||||
Serial.println();
|
||||
}
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
name=Adafruit SleepyDog Library
|
||||
version=1.1.2
|
||||
author=Adafruit
|
||||
maintainer=Adafruit <info@adafruit.com>
|
||||
sentence=Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||
paragraph=Arduino library to use the watchdog timer for system reset and low power sleep.
|
||||
category=Other
|
||||
url=https://github.com/adafruit/Adafruit_SleepyDog
|
||||
architectures=*
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
// Be careful to use a platform-specific conditional include to only make the
|
||||
// code visible for the appropriate platform. Arduino will try to compile and
|
||||
// link all .cpp files regardless of platform.
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(__AVR__)
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#include "WatchdogAVR.h"
|
||||
|
||||
// Define watchdog timer interrupt.
|
||||
ISR(WDT_vect) {
|
||||
// Nothing needs to be done, however interrupt handler must be defined to
|
||||
// prevent a reset.
|
||||
}
|
||||
|
||||
int WatchdogAVR::enable(int maxPeriodMS) {
|
||||
// Pick the closest appropriate watchdog timer value.
|
||||
int actualMS;
|
||||
_setPeriod(maxPeriodMS, _wdto, actualMS);
|
||||
// Enable the watchdog and return the actual countdown value.
|
||||
wdt_enable(_wdto);
|
||||
return actualMS;
|
||||
}
|
||||
|
||||
void WatchdogAVR::reset() {
|
||||
// Reset the watchdog.
|
||||
wdt_reset();
|
||||
}
|
||||
|
||||
void WatchdogAVR::disable() {
|
||||
// Disable the watchdog and clear any saved watchdog timer value.
|
||||
wdt_disable();
|
||||
_wdto = -1;
|
||||
}
|
||||
|
||||
int WatchdogAVR::sleep(int maxPeriodMS) {
|
||||
// Pick the closest appropriate watchdog timer value.
|
||||
int sleepWDTO, actualMS;
|
||||
_setPeriod(maxPeriodMS, sleepWDTO, actualMS);
|
||||
|
||||
// Build watchdog prescaler register value before timing critical code.
|
||||
uint8_t wdps = ((sleepWDTO & 0x08 ? 1 : 0) << WDP3) |
|
||||
((sleepWDTO & 0x04 ? 1 : 0) << WDP2) |
|
||||
((sleepWDTO & 0x02 ? 1 : 0) << WDP1) |
|
||||
((sleepWDTO & 0x01 ? 1 : 0) << WDP0);
|
||||
|
||||
// The next section is timing critical so interrupts are disabled.
|
||||
cli();
|
||||
// First clear any previous watchdog reset.
|
||||
MCUSR &= ~(1<<WDRF);
|
||||
// Now change the watchdog prescaler and interrupt enable bit so the
|
||||
// watchdog reset only triggers the interrupt (and wakes from deep sleep)
|
||||
// and not a full device reset. This is a timing critical section of
|
||||
// code that must happen in 4 cycles.
|
||||
WDTCSR |= (1<<WDCE) | (1<<WDE); // Set WDCE and WDE to enable changes.
|
||||
WDTCSR = wdps; // Set the prescaler bit values.
|
||||
WDTCSR |= (1<<WDIE); // Enable only watchdog interrupts.
|
||||
// Critical section finished, re-enable interrupts.
|
||||
sei();
|
||||
|
||||
// Disable USB if it exists
|
||||
#ifdef USBCON
|
||||
USBCON |= _BV(FRZCLK); // freeze USB clock
|
||||
PLLCSR &= ~_BV(PLLE); // turn off USB PLL
|
||||
USBCON &= ~_BV(USBE); // disable USB
|
||||
#endif
|
||||
|
||||
// Set full power-down sleep mode and go to sleep.
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
sleep_mode();
|
||||
|
||||
// Chip is now asleep!
|
||||
|
||||
// Once awakened by the watchdog execution resumes here.
|
||||
// Start by disabling sleep.
|
||||
sleep_disable();
|
||||
|
||||
// Check if user had the watchdog enabled before sleep and re-enable it.
|
||||
if(_wdto != -1) wdt_enable(_wdto);
|
||||
|
||||
// Return how many actual milliseconds were spent sleeping.
|
||||
return actualMS;
|
||||
}
|
||||
|
||||
void WatchdogAVR::_setPeriod(int maxMS, int &wdto, int &actualMS) {
|
||||
// Note the order of these if statements from highest to lowest is
|
||||
// important so that control flow cascades down to the right value based
|
||||
// on its position in the range of discrete timeouts.
|
||||
if((maxMS >= 8000) || (maxMS == 0)) {
|
||||
wdto = WDTO_8S;
|
||||
actualMS = 8000;
|
||||
} else if(maxMS >= 4000) {
|
||||
wdto = WDTO_4S;
|
||||
actualMS = 4000;
|
||||
} else if(maxMS >= 2000) {
|
||||
wdto = WDTO_2S;
|
||||
actualMS = 2000;
|
||||
} else if(maxMS >= 1000) {
|
||||
wdto = WDTO_1S;
|
||||
actualMS = 1000;
|
||||
} else if(maxMS >= 500) {
|
||||
wdto = WDTO_500MS;
|
||||
actualMS = 500;
|
||||
} else if(maxMS >= 250) {
|
||||
wdto = WDTO_250MS;
|
||||
actualMS = 250;
|
||||
} else if(maxMS >= 120) {
|
||||
wdto = WDTO_120MS;
|
||||
actualMS = 120;
|
||||
} else if(maxMS >= 60) {
|
||||
wdto = WDTO_60MS;
|
||||
actualMS = 60;
|
||||
} else if(maxMS >= 30) {
|
||||
wdto = WDTO_30MS;
|
||||
actualMS = 30;
|
||||
} else {
|
||||
wdto = WDTO_15MS;
|
||||
actualMS = 15;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#ifndef WATCHDOGAVR_H
|
||||
#define WATCHDOGAVR_H
|
||||
|
||||
class WatchdogAVR {
|
||||
public:
|
||||
WatchdogAVR():
|
||||
_wdto(-1)
|
||||
{}
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int enable(int maxPeriodMS = 0);
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void reset();
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void disable();
|
||||
|
||||
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||
// desired period of time. The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
int sleep(int maxPeriodMS = 0);
|
||||
|
||||
private:
|
||||
// Pick the closest (but not higher) watchdog timer value from the provided
|
||||
// maximum period. Sets wdto to the chosen period value suitable for
|
||||
// passing to wdt_enable(), and actualMS to the chosen period value in
|
||||
// milliseconds. A max value of 0 will pick the longest value possible.
|
||||
void _setPeriod(int maxMS, int &wdto, int &actualMS);
|
||||
|
||||
// Keep the last selected watchdog timer period so that the watchdog can be
|
||||
// re-enabled at that rate after sleep. A value of -1 means no watchdog
|
||||
// timer was enabled.
|
||||
int _wdto;
|
||||
};
|
||||
|
||||
#endif
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
// Be careful to use a platform-specific conditional include to only make the
|
||||
// code visible for the appropriate platform. Arduino will try to compile and
|
||||
// link all .cpp files regardless of platform.
|
||||
#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
|
||||
#include <kinetis.h>
|
||||
#include "WatchdogKinetisK.h"
|
||||
|
||||
static void one_bus_cycle(void) __attribute__((always_inline));
|
||||
static void watchdog_config(int cfg, int val);
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int WatchdogKinetisKseries::enable(int maxPeriodMS)
|
||||
{
|
||||
if (maxPeriodMS < 4) {
|
||||
maxPeriodMS = 8000; // default is 8 seconds
|
||||
}
|
||||
if (setting != maxPeriodMS) {
|
||||
watchdog_config(WDOG_STCTRLH_WDOGEN, maxPeriodMS);
|
||||
setting = maxPeriodMS;
|
||||
}
|
||||
return maxPeriodMS;
|
||||
}
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void WatchdogKinetisKseries::reset()
|
||||
{
|
||||
__disable_irq();
|
||||
WDOG_REFRESH = 0xA602;
|
||||
WDOG_REFRESH = 0xB480;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void WatchdogKinetisKseries::disable()
|
||||
{
|
||||
if (setting > 0) {
|
||||
watchdog_config(0, 4);
|
||||
setting = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Enter the lowest power sleep mode for the desired period of time. The
|
||||
// passed in period (in milliseconds) is just a suggestion and a lower value
|
||||
// might be picked if the hardware does not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
int WatchdogKinetisKseries::sleep(int maxPeriodMS)
|
||||
{
|
||||
if (maxPeriodMS <= 0) return 0;
|
||||
// TODO....
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void watchdog_config(int cfg, int val)
|
||||
{
|
||||
__disable_irq();
|
||||
WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;
|
||||
WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
|
||||
one_bus_cycle();
|
||||
WDOG_STCTRLH = cfg | WDOG_STCTRLH_ALLOWUPDATE;
|
||||
WDOG_TOVALH = val >> 16;
|
||||
WDOG_TOVALL = val;
|
||||
WDOG_PRESC = 0;
|
||||
__enable_irq();
|
||||
for (int i=0; i < 256; i++) {
|
||||
one_bus_cycle();
|
||||
}
|
||||
}
|
||||
|
||||
static void one_bus_cycle(void)
|
||||
{
|
||||
__asm__ volatile ("nop");
|
||||
#if (F_CPU / F_BUS) > 1
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 2
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 3
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 4
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 5
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 6
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
#if (F_CPU / F_BUS) > 7
|
||||
__asm__ volatile ("nop");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef WATCHDOGKINETISK_H
|
||||
#define WATCHDOGKINETISK_H
|
||||
|
||||
class WatchdogKinetisKseries {
|
||||
public:
|
||||
WatchdogKinetisKseries(): setting(0) {}
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int enable(int maxPeriodMS = 0);
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void reset();
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void disable();
|
||||
|
||||
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||
// desired period of time. The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
//
|
||||
// NOTE: This is currently not implemented on the SAMD21!
|
||||
int sleep(int maxPeriodMS = 0);
|
||||
|
||||
private:
|
||||
int setting;
|
||||
};
|
||||
|
||||
#endif
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
// Be careful to use a platform-specific conditional include to only make the
|
||||
// code visible for the appropriate platform. Arduino will try to compile and
|
||||
// link all .cpp files regardless of platform.
|
||||
#if defined(__MKL26Z64__)
|
||||
|
||||
#include <kinetis.h>
|
||||
#include "WatchdogKinetisL.h"
|
||||
|
||||
// Normally the watchdog is disabled at startup. This removes the startup
|
||||
// code. The watchdog will be active with 1024 ms timeout. Hopefully the
|
||||
// user will configure the watchdog and begin resetting it before it causes
|
||||
// a reboot. There is no way to start up without the watchdog and then
|
||||
// enable it later...
|
||||
extern "C" void startup_early_hook(void) {}
|
||||
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int WatchdogKinetisLseries::enable(int maxPeriodMS)
|
||||
{
|
||||
// The watchdog can only be programmed once. Then it's forever
|
||||
// locked to this setting (until the chip reboots).
|
||||
if (maxPeriodMS <= 0 || maxPeriodMS > 256) {
|
||||
SIM_COPC = 12;
|
||||
} else if (maxPeriodMS > 32) {
|
||||
SIM_COPC = 8;
|
||||
} else {
|
||||
SIM_COPC = 4;
|
||||
}
|
||||
// Read the actual setting.
|
||||
int val = SIM_COPC & 12;
|
||||
if (val == 12) return 1024;
|
||||
if (val == 8) return 256;
|
||||
return 32;
|
||||
}
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void WatchdogKinetisLseries::reset()
|
||||
{
|
||||
__disable_irq();
|
||||
SIM_SRVCOP = 0x55;
|
||||
SIM_SRVCOP = 0xAA;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void WatchdogKinetisLseries::disable()
|
||||
{
|
||||
// no can do....
|
||||
// The watchdog timer in this chip is write-once.
|
||||
// The chip boots up with the watchdog at 1024 ms.
|
||||
// You only get to configure it once. Then it
|
||||
// remains locked to that setting, until a reboot.
|
||||
}
|
||||
|
||||
// Enter the lowest power sleep mode for the desired period of time. The
|
||||
// passed in period (in milliseconds) is just a suggestion and a lower value
|
||||
// might be picked if the hardware does not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
int WatchdogKinetisLseries::sleep(int maxPeriodMS)
|
||||
{
|
||||
if (maxPeriodMS <= 0) return 0;
|
||||
// TODO....
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#ifndef WATCHDOGKINETISL_H
|
||||
#define WATCHDOGKINETISL_H
|
||||
|
||||
class WatchdogKinetisLseries {
|
||||
public:
|
||||
WatchdogKinetisLseries() {}
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int enable(int maxPeriodMS = 0);
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void reset();
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void disable();
|
||||
|
||||
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||
// desired period of time. The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware does
|
||||
// not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
//
|
||||
// NOTE: This is currently not implemented on the SAMD21!
|
||||
int sleep(int maxPeriodMS = 0);
|
||||
};
|
||||
|
||||
#endif
|
||||
Executable
+240
@@ -0,0 +1,240 @@
|
||||
// Requires Adafruit_ASFcore library!
|
||||
|
||||
// Be careful to use a platform-specific conditional include to only make the
|
||||
// code visible for the appropriate platform. Arduino will try to compile and
|
||||
// link all .cpp files regardless of platform.
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
|
||||
#include <sam.h>
|
||||
#include "WatchdogSAMD.h"
|
||||
|
||||
int WatchdogSAMD::enable(int maxPeriodMS, bool isForSleep) {
|
||||
// Enable the watchdog with a period up to the specified max period in
|
||||
// milliseconds.
|
||||
|
||||
// Review the watchdog section from the SAMD21 datasheet section 17:
|
||||
// http://www.atmel.com/images/atmel-42181-sam-d21_datasheet.pdf
|
||||
|
||||
int cycles;
|
||||
uint8_t bits;
|
||||
|
||||
if(!_initialized) _initialize_wdt();
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
WDT->CTRLA.reg = 0; // Disable watchdog for config
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
WDT->CTRL.reg = 0; // Disable watchdog for config
|
||||
while(WDT->STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
|
||||
// You'll see some occasional conversion here compensating between
|
||||
// milliseconds (1000 Hz) and WDT clock cycles (~1024 Hz). The low-
|
||||
// power oscillator used by the WDT ostensibly runs at 32,768 Hz with
|
||||
// a 1:32 prescale, thus 1024 Hz, though probably not super precise.
|
||||
|
||||
if((maxPeriodMS >= 16000) || !maxPeriodMS) {
|
||||
cycles = 16384;
|
||||
bits = 0xB;
|
||||
} else {
|
||||
cycles = (maxPeriodMS * 1024L + 500) / 1000; // ms -> WDT cycles
|
||||
if(cycles >= 8192) {
|
||||
cycles = 8192;
|
||||
bits = 0xA;
|
||||
} else if(cycles >= 4096) {
|
||||
cycles = 4096;
|
||||
bits = 0x9;
|
||||
} else if(cycles >= 2048) {
|
||||
cycles = 2048;
|
||||
bits = 0x8;
|
||||
} else if(cycles >= 1024) {
|
||||
cycles = 1024;
|
||||
bits = 0x7;
|
||||
} else if(cycles >= 512) {
|
||||
cycles = 512;
|
||||
bits = 0x6;
|
||||
} else if(cycles >= 256) {
|
||||
cycles = 256;
|
||||
bits = 0x5;
|
||||
} else if(cycles >= 128) {
|
||||
cycles = 128;
|
||||
bits = 0x4;
|
||||
} else if(cycles >= 64) {
|
||||
cycles = 64;
|
||||
bits = 0x3;
|
||||
} else if(cycles >= 32) {
|
||||
cycles = 32;
|
||||
bits = 0x2;
|
||||
} else if(cycles >= 16) {
|
||||
cycles = 16;
|
||||
bits = 0x1;
|
||||
} else {
|
||||
cycles = 8;
|
||||
bits = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
// Watchdog timer on SAMD is a slightly different animal than on AVR.
|
||||
// On AVR, the WTD timeout is configured in one register and then an
|
||||
// interrupt can optionally be enabled to handle the timeout in code
|
||||
// (as in waking from sleep) vs resetting the chip. Easy.
|
||||
// On SAMD, when the WDT fires, that's it, the chip's getting reset.
|
||||
// Instead, it has an "early warning interrupt" with a different set
|
||||
// interval prior to the reset. For equivalent behavior to the AVR
|
||||
// library, this requires a slightly different configuration depending
|
||||
// whether we're coming from the sleep() function (which needs the
|
||||
// interrupt), or just enable() (no interrupt, we want the chip reset
|
||||
// unless the WDT is cleared first). In the sleep case, 'windowed'
|
||||
// mode is used in order to allow access to the longest available
|
||||
// sleep interval (about 16 sec); the WDT 'period' (when a reset
|
||||
// occurs) follows this and is always just set to the max, since the
|
||||
// interrupt will trigger first. In the enable case, windowed mode
|
||||
// is not used, the WDT period is set and that's that.
|
||||
// The 'isForSleep' argument determines which behavior is used;
|
||||
// this isn't present in the AVR code, just here. It defaults to
|
||||
// 'false' so existing Arduino code works as normal, while the sleep()
|
||||
// function (later in this file) explicitly passes 'true' to get the
|
||||
// alternate behavior.
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
if(isForSleep) {
|
||||
WDT->INTENSET.bit.EW = 1; // Enable early warning interrupt
|
||||
WDT->CONFIG.bit.PER = 0xB; // Period = max
|
||||
WDT->CONFIG.bit.WINDOW = bits; // Set time of interrupt
|
||||
WDT->CTRLA.bit.WEN = 1; // Enable window mode
|
||||
while(WDT->SYNCBUSY.reg); // Sync CTRL write
|
||||
} else {
|
||||
WDT->INTENCLR.bit.EW = 1; // Disable early warning interrupt
|
||||
WDT->CONFIG.bit.PER = bits; // Set period for chip reset
|
||||
WDT->CTRLA.bit.WEN = 0; // Disable window mode
|
||||
while(WDT->SYNCBUSY.reg); // Sync CTRL write
|
||||
}
|
||||
|
||||
reset(); // Clear watchdog interval
|
||||
WDT->CTRLA.bit.ENABLE = 1; // Start watchdog now!
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
if(isForSleep) {
|
||||
WDT->INTENSET.bit.EW = 1; // Enable early warning interrupt
|
||||
WDT->CONFIG.bit.PER = 0xB; // Period = max
|
||||
WDT->CONFIG.bit.WINDOW = bits; // Set time of interrupt
|
||||
WDT->CTRL.bit.WEN = 1; // Enable window mode
|
||||
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||
} else {
|
||||
WDT->INTENCLR.bit.EW = 1; // Disable early warning interrupt
|
||||
WDT->CONFIG.bit.PER = bits; // Set period for chip reset
|
||||
WDT->CTRL.bit.WEN = 0; // Disable window mode
|
||||
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||
}
|
||||
|
||||
reset(); // Clear watchdog interval
|
||||
WDT->CTRL.bit.ENABLE = 1; // Start watchdog now!
|
||||
while(WDT->STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
|
||||
return (cycles * 1000L + 512) / 1024; // WDT cycles -> ms
|
||||
}
|
||||
|
||||
void WatchdogSAMD::reset() {
|
||||
// Write the watchdog clear key value (0xA5) to the watchdog
|
||||
// clear register to clear the watchdog timer and reset it.
|
||||
WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
|
||||
#if defined(__SAMD51__)
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
while(WDT->STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WatchdogSAMD::disable() {
|
||||
#if defined(__SAMD51__)
|
||||
WDT->CTRLA.bit.ENABLE = 0;
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
WDT->CTRL.bit.ENABLE = 0;
|
||||
while(WDT->STATUS.bit.SYNCBUSY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDT_Handler(void) {
|
||||
// ISR for watchdog early warning, DO NOT RENAME!
|
||||
#if defined(__SAMD51__)
|
||||
WDT->CTRLA.bit.ENABLE = 0; // Disable watchdog
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
WDT->CTRL.bit.ENABLE = 0; // Disable watchdog
|
||||
while(WDT->STATUS.bit.SYNCBUSY); // Sync CTRL write
|
||||
|
||||
#endif
|
||||
WDT->INTFLAG.bit.EW = 1; // Clear interrupt flag
|
||||
}
|
||||
|
||||
int WatchdogSAMD::sleep(int maxPeriodMS) {
|
||||
|
||||
int actualPeriodMS = enable(maxPeriodMS, true); // true = for sleep
|
||||
|
||||
// Enable standby sleep mode (deepest sleep) and activate.
|
||||
// Insights from Atmel ASF library.
|
||||
#if (SAMD20 || SAMD21)
|
||||
// Don't fully power down flash when in sleep
|
||||
NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;
|
||||
#endif
|
||||
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
|
||||
|
||||
__DSB(); // Data sync to ensure outgoing memory accesses complete
|
||||
__WFI(); // Wait for interrupt (places device in sleep mode)
|
||||
|
||||
// Code resumes here on wake (WDT early warning interrupt).
|
||||
// Bug: the return value assumes the WDT has run its course;
|
||||
// incorrect if the device woke due to an external interrupt.
|
||||
// Without an external RTC there's no way to provide a correct
|
||||
// sleep period in the latter case...but at the very least,
|
||||
// might indicate said condition occurred by returning 0 instead
|
||||
// (assuming we can pin down which interrupt caused the wake).
|
||||
|
||||
return actualPeriodMS;
|
||||
}
|
||||
|
||||
void WatchdogSAMD::_initialize_wdt() {
|
||||
// One-time initialization of watchdog timer.
|
||||
// Insights from rickrlh and rbrucemtl in Arduino forum!
|
||||
|
||||
#if defined(__SAMD51__)
|
||||
// SAMD51 WDT uses OSCULP32k as input clock now
|
||||
// section: 20.5.3
|
||||
OSC32KCTRL->OSCULP32K.reg =
|
||||
OSC32KCTRL_OSCULP32K_EN1K | OSC32KCTRL_OSCULP32K_EN32K;
|
||||
|
||||
// Enable WDT early-warning interrupt
|
||||
NVIC_DisableIRQ(WDT_IRQn);
|
||||
NVIC_ClearPendingIRQ(WDT_IRQn);
|
||||
NVIC_SetPriority(WDT_IRQn, 0); // Top priority
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
|
||||
while(WDT->SYNCBUSY.reg);
|
||||
#else
|
||||
// Generic clock generator 2, divisor = 32 (2^(DIV+1))
|
||||
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4);
|
||||
// Enable clock generator 2 using low-power 32KHz oscillator.
|
||||
// With /32 divisor above, this yields 1024Hz(ish) clock.
|
||||
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) |
|
||||
GCLK_GENCTRL_GENEN |
|
||||
GCLK_GENCTRL_SRC_OSCULP32K |
|
||||
GCLK_GENCTRL_DIVSEL;
|
||||
while(GCLK->STATUS.bit.SYNCBUSY);
|
||||
// WDT clock = clock gen 2
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID_WDT |
|
||||
GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK2;
|
||||
|
||||
// Enable WDT early-warning interrupt
|
||||
NVIC_DisableIRQ(WDT_IRQn);
|
||||
NVIC_ClearPendingIRQ(WDT_IRQn);
|
||||
NVIC_SetPriority(WDT_IRQn, 0); // Top priority
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
#endif
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
#endif // defined(ARDUINO_ARCH_SAMD)
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef WATCHDOGSAMD_H
|
||||
#define WATCHDOGSAMD_H
|
||||
|
||||
class WatchdogSAMD {
|
||||
public:
|
||||
WatchdogSAMD():
|
||||
_initialized(false)
|
||||
{}
|
||||
|
||||
// Enable the watchdog timer to reset the machine after a period of time
|
||||
// without any calls to reset(). The passed in period (in milliseconds)
|
||||
// is just a suggestion and a lower value might be picked if the hardware
|
||||
// does not support the exact desired value.
|
||||
// User code should NOT set the 'isForSleep' argument either way --
|
||||
// it's used internally by the library, but your sketch should leave this
|
||||
// out when calling enable(), just let the default have its way.
|
||||
//
|
||||
// The actual period (in milliseconds) before a watchdog timer reset is
|
||||
// returned.
|
||||
int enable(int maxPeriodMS = 0, bool isForSleep = false);
|
||||
|
||||
// Reset or 'kick' the watchdog timer to prevent a reset of the device.
|
||||
void reset();
|
||||
|
||||
// Completely disable the watchdog timer.
|
||||
void disable();
|
||||
|
||||
// Enter the lowest power sleep mode (using the watchdog timer) for the
|
||||
// desired period of time. The passed in period (in milliseconds) is
|
||||
// just a suggestion and a lower value might be picked if the hardware
|
||||
// does not support the exact desired value
|
||||
//
|
||||
// The actual period (in milliseconds) that the hardware was asleep will be
|
||||
// returned.
|
||||
int sleep(int maxPeriodMS = 0);
|
||||
|
||||
private:
|
||||
void _initialize_wdt();
|
||||
|
||||
bool _initialized;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user