diff --git a/include/libopencm3/swm050/sysctl.h b/include/libopencm3/swm050/sysctl.h index 6fa642d0..40187c43 100644 --- a/include/libopencm3/swm050/sysctl.h +++ b/include/libopencm3/swm050/sysctl.h @@ -31,6 +31,14 @@ #include #include +/** @defgroup sysctl_bit_defs SYSCTL register bit definitions +@{*/ +#define SYSCTL_SYS_CFG_2_SLEEP (1 << 4) +#define SYSCTL_SYS_CFG_1_TIMERSE0 (1 << 6) +#define SYSCTL_SYS_CFG_1_TIMERSE1 (1 << 17) +#define SYSCTL_SYS_CFG_1_WDT (1 << 4) +/**@}*/ + /** @defgroup sysctl_register SYSCTL Registers * @note System configuration registers * @{*/ diff --git a/include/libopencm3/swm050/wdt.h b/include/libopencm3/swm050/wdt.h new file mode 100644 index 00000000..3607ecd3 --- /dev/null +++ b/include/libopencm3/swm050/wdt.h @@ -0,0 +1,71 @@ +/** @defgroup wdt_defines Watchdog Defines + * + * @brief Defined Constants and Types for the SWM050 Watchdog + * + * @ingroup SWM050_defines + * + * LGPL License Terms @ref lgpl_license + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2019 Caleb Szalacinski + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ +#ifndef LIBOPENCM3_WDT_H +#define LIBOPENCM3_WDT_H + +#include +#include + +/* Watchdog mode definitions */ +/** @defgroup wdt_modes Watchdog mode +@{*/ +enum wdt_modes { + /* On timeout, reset the system */ + WDT_MODE_RESET, + /* On timeout, generate an interrupt. If another timeout occurs without + the interrupt being cleared, reset the system. */ + WDT_MODE_INT +}; +/**@}*/ + +/** @defgroup wdt_registers Watchdog Registers +@{*/ +#define WDT_CR MMIO32(WDT_BASE + 0x0) +#define WDT_TORR MMIO32(WDT_BASE + 0x04) +#define WDT_CCVR MMIO32(WDT_BASE + 0x08) +#define WDT_CRR MMIO32(WDT_BASE + 0x0C) +#define WDT_STAT MMIO32(WDT_BASE + 0x10) +#define WDT_EOI MMIO32(WDT_BASE + 0x14) +/**@}*/ + +BEGIN_DECLS + +void wdt_setup(enum wdt_modes mode, uint8_t time1, uint8_t time2); +void wdt_enable(bool en); +void wdt_mode(enum wdt_modes mode); +void wdt_reset(void); +bool wdt_int_status(void); +void wdt_clear_int(void); +void wdt_clock_enable(bool en); +uint32_t wdt_get_value(void); +void wdt_set_time(uint8_t time1, uint8_t time2); + +END_DECLS + +#endif +/**@}*/ diff --git a/lib/swm050/Makefile b/lib/swm050/Makefile index 10f03e6a..ab57cf20 100644 --- a/lib/swm050/Makefile +++ b/lib/swm050/Makefile @@ -38,6 +38,7 @@ OBJS += flash.o OBJS += gpio.o OBJS += pwr.o OBJS += syscon.o +OBJS += wdt.o VPATH += ../cm3 include ../Makefile.include diff --git a/lib/swm050/pwr.c b/lib/swm050/pwr.c index 0be19053..ef51d532 100644 --- a/lib/swm050/pwr.c +++ b/lib/swm050/pwr.c @@ -37,6 +37,6 @@ not get locked out of the MCU. */ void pwr_sleep(void) { - SYSCTL_SYS_CFG_2 |= (1<<4); + SYSCTL_SYS_CFG_2 |= SYSCTL_SYS_CFG_2_SLEEP; } /**@}*/ diff --git a/lib/swm050/wdt.c b/lib/swm050/wdt.c new file mode 100644 index 00000000..7e144b06 --- /dev/null +++ b/lib/swm050/wdt.c @@ -0,0 +1,168 @@ +/** @defgroup wdg_file Watchdog peripheral API + * @brief SWM050 WDT API. + * @ingroup peripheral_apis + * LGPL License Terms @ref lgpl_license + * @author @htmlonly © @endhtmlonly 2019 + * Caleb Szalacinski + */ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2019 Caleb Szalacinski + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +/**@{*/ +#include +#include + +/*---------------------------------------------------------------------------*/ +/** Sets up the WDT before the call to wdt_enable(). + +@param mode passed to wdt_mode() + +@param time1 passed to wdt_set_time() + +@param time2 passed to wdt_set_time() +*/ +void wdt_setup(enum wdt_modes mode, uint8_t time1, uint8_t time2) +{ + wdt_clock_enable(1); + wdt_set_time(time1, time2); + wdt_mode(mode); + wdt_reset(); +} +/*---------------------------------------------------------------------------*/ +/** Enables the WDT. + +If WDT_MODE_INT is used, the interrupt should also be enabled +using the NVIC before enabling the WDT. + +@param en enable +*/ +void wdt_enable(bool en) +{ + if (en) { + WDT_CR |= 0x1; + } else { + WDT_CR &= ~0x1; + } +} + +/*---------------------------------------------------------------------------*/ +/** Sets the WDT's mode of operation. + +@param mode The mode of operation @ref wdt_modes +*/ +void wdt_mode(enum wdt_modes mode) +{ + if (mode == WDT_MODE_INT) { + WDT_CR |= (1 << 1); + } else { + WDT_CR &= ~(1 << 1); + } +} + +/*---------------------------------------------------------------------------*/ +/** Restarts the WDT's counter. + +The "feed the dog" operation. Must be called periodically to avoid a timeout. +Calling this also clears any WDT interrupts. +*/ +void wdt_reset(void) +{ + WDT_CRR = 0x76; +} + +/*---------------------------------------------------------------------------*/ +/** Gets the WDT's interrupt status. + + Only useful in WDT_MODE_INT. + +@return The WDT's interrupt status. True if an interrupt has not been cleared. +*/ +bool wdt_int_status(void) +{ + return WDT_STAT & 0x1; +} + +/*---------------------------------------------------------------------------*/ +/** Clears the WDT's interrupt. + + Only useful in WDT_MODE_INT. +*/ +void wdt_clear_int(void) +{ + /* Read register to clear the interrupt */ + uint32_t dummy = WDT_EOI; + /* Does nothing, but suppresses a -Wunused-variable warning */ + (void)dummy; +} + +/*---------------------------------------------------------------------------*/ +/** Enables the WDT's clock. + +@param en True to enable, false to disable +*/ +void wdt_clock_enable(bool en) +{ + if (en) { + SYSCTL_SYS_CFG_1 |= SYSCTL_SYS_CFG_1_WDT; + } else { + SYSCTL_SYS_CFG_1 &= ~SYSCTL_SYS_CFG_1_WDT; + } +} + +/*---------------------------------------------------------------------------*/ +/** Gets the current WDT counter value. + +The vendor-supplied documentation for the WDT_CCVR register appears to be +incorrect, and does not seem to be 1 bit wide, which would make no sense. + +@return The current WDT counter value +*/ +uint32_t wdt_get_value(void) +{ + return WDT_CCVR; +} + +/*---------------------------------------------------------------------------*/ +/** Sets the WDT's initial counter values. + +Both time1 and time2 follow the equation 2^(8 + i), where i is a value from +0 to 15, and where the result is in clock cycles. + +For example: + time1 = 15 + 2^(8 + time1) / 18Mhz = 0.466s + +The majority of the vendor-supplied documentation appears to be completely +incorrect about the equation used for these counters. + +@param time1 The timer value used in both modes. In WDT_MODE_RESET, this value +counts down to 0 and resets the system. In WDT_MODE_INT, this value counts down +to 0, generates a WDT interrupt, loads time2 into the counter, and counts down. +Only the 4 least significant bits of this value are used, e.g. 0 to 15. + +@param time2 The timer value used after time1 in mode WDT_MODE_INT. If this +counts down to 0, and the WDT interrupt has not been cleared, the system resets. +This has no use in mode WDT_MODE_RESET. +Only the 4 least significant bits of this value are used, e.g. 0 to 15. +*/ +void wdt_set_time(uint8_t time1, uint8_t time2) +{ + WDT_TORR = ((0xF & time1) << 4) | (0xF & time2); +} + +/**@}*/