git subrepo clone https://github.com/libopencm3/libopencm3
subrepo: subdir: "libopencm3" merged: "f5813a54" upstream: origin: "https://github.com/libopencm3/libopencm3" branch: "master" commit: "f5813a54" git-subrepo: version: "0.4.3" origin: "???" commit: "???"
This commit is contained in:
45
libopencm3/lib/swm050/Makefile
Normal file
45
libopencm3/lib/swm050/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
##
|
||||
## This file is part of the libopencm3 project.
|
||||
##
|
||||
## Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io>
|
||||
##
|
||||
## 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 <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
LIBNAME = libopencm3_swm050
|
||||
SRCLIBDIR ?= ..
|
||||
|
||||
CC = $(PREFIX)gcc
|
||||
AR = $(PREFIX)ar
|
||||
TGT_CFLAGS = -Os \
|
||||
-Wall -Wextra -Wimplicit-function-declaration \
|
||||
-Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes \
|
||||
-Wundef -Wshadow \
|
||||
-I../../include -fno-common \
|
||||
-mcpu=cortex-m0 $(FP_FLAGS) -mthumb -Wstrict-prototypes \
|
||||
-ffunction-sections -fdata-sections -MD -DSWM050
|
||||
TGT_CFLAGS += $(DEBUG_FLAGS)
|
||||
TGT_CFLAGS += $(STANDARD_FLAGS)
|
||||
ARFLAGS = rcs
|
||||
|
||||
OBJS += clk.o
|
||||
OBJS += flash.o
|
||||
OBJS += gpio.o
|
||||
OBJS += pwr.o
|
||||
OBJS += syscon.o
|
||||
OBJS += timer.o
|
||||
OBJS += wdt.o
|
||||
VPATH += ../cm3
|
||||
|
||||
include ../Makefile.include
|
||||
85
libopencm3/lib/swm050/clk.c
Normal file
85
libopencm3/lib/swm050/clk.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/** @defgroup clk_file Clock peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
* @brief SWM050 Clock API.
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/clk.h>
|
||||
#include <libopencm3/swm050/sysctl.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Setup and change the system clock multiplier and divider
|
||||
|
||||
Change system clock speed and wait for the clock to stabilize. The clock only
|
||||
needs time to stabilize on the first invocation of this function. This should be
|
||||
run at startup if you want to have a stable clock before doing anything.
|
||||
|
||||
@param[in] mhz Base clock speed @ref clk_speeds
|
||||
The base clock speed, before the clock divider
|
||||
|
||||
@param[in] div Clock divider
|
||||
Takes values from 0 to 1023 (in reality the possible values are the even
|
||||
numbers from 2 to 1022, as well as the number 1). Anything more than the
|
||||
first 10 bits is stripped off of the value. If the value is 0, it will
|
||||
be treated as a 1. All odd values other than 1 are rounded down to the
|
||||
closest even value, due to the fact that all odd values are treated by
|
||||
the register as a 1, which would likely be unexpected. A value of 0
|
||||
would also normally be treated as a 2, which would also be unexpected
|
||||
behavior.
|
||||
*/
|
||||
void clk_speed(enum clk_speeds mhz, uint16_t div)
|
||||
{
|
||||
static bool first_run = true;
|
||||
|
||||
if (first_run) {
|
||||
first_run = false;
|
||||
clk_speed(CLK_18MHZ, 1);
|
||||
|
||||
for (uint16_t i = 0; i < 10000; ++i) {
|
||||
__asm__("nop");
|
||||
}
|
||||
|
||||
/* The speed doesn't need to be changed
|
||||
a second time if the user wants 18Mhz. */
|
||||
if ((mhz == CLK_18MHZ) && (div <= 1)) {
|
||||
return;
|
||||
}
|
||||
if ((mhz == CLK_36MHZ) && (div == 2)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mhz == CLK_36MHZ) {
|
||||
SYSCTL_SYS_DBLF |= BIT0;
|
||||
} else {
|
||||
SYSCTL_SYS_DBLF &= ~BIT0;
|
||||
}
|
||||
|
||||
if (div <= 1) {
|
||||
SYSCTL_SYS_CFG_0 |= BIT0;
|
||||
} else {
|
||||
uint32_t masked_reg32 = SYSCTL_SYS_CFG_0 & CLK_MASK;
|
||||
SYSCTL_SYS_CFG_0 = masked_reg32 | (div & ~(CLK_MASK | 0x1));
|
||||
}
|
||||
}
|
||||
/**@}*/
|
||||
97
libopencm3/lib/swm050/flash.c
Normal file
97
libopencm3/lib/swm050/flash.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/** @defgroup flash_file Flash peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
* @brief SWM050 Flash API.
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/flash.h>
|
||||
|
||||
/* Internal function pointers to the ROM flash API */
|
||||
#define IAP_WR (void *)(0x1000AB)
|
||||
#define IAP_E (void *)(0x100127)
|
||||
|
||||
uint32_t (*iap_write_read)(uint32_t *, uint32_t *, uint8_t, uint8_t) = IAP_WR;
|
||||
uint32_t (*iap_erase)(void) = IAP_E;
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Write to the user flash
|
||||
|
||||
Writes words to the 0.5k user flash area.
|
||||
Must be performed only when the system clock is 18Mhz.
|
||||
|
||||
@param[in] dest Destination address
|
||||
The memory area to copy to.
|
||||
From 0x00 - 0x1FC, as long as it is word-aligned
|
||||
|
||||
@param[in] src Source address
|
||||
The memory area to copy from.
|
||||
|
||||
@param[in] cnt Number of words to write
|
||||
From 1-128 as long as (dest + (cnt * 4)) < 0x200
|
||||
|
||||
@return 1 if successful, 0 if error
|
||||
|
||||
*/
|
||||
uint32_t flash_write(uint32_t *dest, uint32_t *src, uint8_t cnt)
|
||||
{
|
||||
return iap_write_read(dest, src, cnt, 1);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Read from the user flash
|
||||
|
||||
Reads words from the 0.5k user flash area.
|
||||
Must be performed only when the system clock is 18Mhz.
|
||||
|
||||
@param[in] src Source address
|
||||
The memory area to copy from.
|
||||
From 0x00 - 0x1FC, as long as it is word-aligned
|
||||
|
||||
@param[out] dest Destination address
|
||||
The memory area to copy to.
|
||||
|
||||
@param[in] cnt Number of words to read
|
||||
From 1 - 128 as long as (src + (cnt * 4)) < 0x200
|
||||
|
||||
@return 1 if successful, 0 if error
|
||||
|
||||
*/
|
||||
uint32_t flash_read(uint32_t *src, uint32_t *dest, uint8_t cnt)
|
||||
{
|
||||
return iap_write_read(src, dest, cnt, 0);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Erase the user flash
|
||||
|
||||
Erases the entire 0.5k user flash area.
|
||||
Must be performed only when the system clock is 18Mhz.
|
||||
|
||||
@return 1 if successful, 0 if error
|
||||
|
||||
*/
|
||||
uint32_t flash_erase(void)
|
||||
{
|
||||
return iap_erase();
|
||||
}
|
||||
/**@}*/
|
||||
254
libopencm3/lib/swm050/gpio.c
Normal file
254
libopencm3/lib/swm050/gpio.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/** @defgroup gpio_file GPIO peripheral API
|
||||
* @brief SWM050 GPIO API.
|
||||
* @ingroup peripheral_apis
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Icenowy Zheng <icenowy@aosc.io>
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io>
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/gpio.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set a Group of Pins
|
||||
|
||||
Set one or more pins of GPIO to 1. Please note that this chip doesn't support
|
||||
atomic pin setting.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_set(uint16_t gpios)
|
||||
{
|
||||
GPIO_ADATA |= gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Clear a Group of Pins
|
||||
|
||||
Set one or more pins of GPIO to 0. Please note that this chip doesn't support
|
||||
atomic pin setting.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_clear(uint16_t gpios)
|
||||
{
|
||||
GPIO_ADATA &= ~gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Read a Group of Pins.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be read, use bitwise OR '|' to separate
|
||||
them.
|
||||
@return The pin values as a bitfield. The bit position of the pin
|
||||
value returned corresponds to the pin number.
|
||||
*/
|
||||
uint16_t gpio_get(uint16_t gpios)
|
||||
{
|
||||
return GPIO_AEXT & gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Toggle a Group of Pins
|
||||
|
||||
Toggle one or more pins of GPIO. The non-toggled pins are not affected.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_toggle(uint16_t gpios)
|
||||
{
|
||||
uint32_t curr_status = GPIO_ADATA & gpios;
|
||||
GPIO_ADATA = (GPIO_ADATA & (~gpios)) | (~curr_status);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set the direction of a Group of Pins to Input
|
||||
|
||||
Set the direction of one or more pins of GPIO to input.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_input(uint16_t gpios)
|
||||
{
|
||||
GPIO_ADIR &= ~gpios;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Set the direction of a Group of Pins to Output
|
||||
|
||||
Set the direction of one or more pins of GPIO to output.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_output(uint16_t gpios)
|
||||
{
|
||||
GPIO_ADIR |= gpios;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Sets the pins as external interrupts, rather than normal GPIO
|
||||
|
||||
Enable interrupts on the selected pins. If you want to quickly
|
||||
switch on and off interrupts, use gpio_int_mask() after calling this.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
|
||||
@param[in] en True to enable, false to disable.
|
||||
*/
|
||||
void gpio_int_enable(uint16_t gpios, bool en)
|
||||
{
|
||||
if (en) {
|
||||
GPIO_INTEN_A |= gpios;
|
||||
} else {
|
||||
GPIO_INTEN_A &= ~gpios;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Sets bits in the interrupt mask
|
||||
|
||||
When interrupts are masked, it prevents them from being received, which is a
|
||||
quicker way to turn on and off GPIO interrupts (after calling gpio_int_en()).
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
|
||||
@param[in] masked Pin mask selection @ref gpio_int_masked
|
||||
Whether to mask or unmask pins.
|
||||
*/
|
||||
void gpio_int_mask(uint16_t gpios, enum gpio_int_masked masked)
|
||||
{
|
||||
if (masked) {
|
||||
GPIO_INTMASK_A |= gpios;
|
||||
} else {
|
||||
GPIO_INTMASK_A &= ~gpios;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Sets whether the pins are edge triggered or level triggered
|
||||
|
||||
Sets whether the pins are edge triggered or level triggered. Edge-triggered
|
||||
interrupt bits must be cleared by software.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
|
||||
@param[in] type Trigger Type @ref gpio_trig_type
|
||||
Level or edge triggered
|
||||
*/
|
||||
void gpio_int_type(uint16_t gpios, enum gpio_trig_type type)
|
||||
{
|
||||
if (type) {
|
||||
GPIO_INTLEVEL_A |= gpios;
|
||||
} else {
|
||||
GPIO_INTLEVEL_A &= ~gpios;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Sets the interrupt trigger polarity
|
||||
|
||||
Sets whether the interrupt is triggered by a high or low level/edge.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
|
||||
@param[in] pol Polarity @ref gpio_pol
|
||||
High or low level/edge
|
||||
*/
|
||||
void gpio_int_pol(uint16_t gpios, enum gpio_pol pol)
|
||||
{
|
||||
if (pol) {
|
||||
GPIO_INTPOLARITY_A |= gpios;
|
||||
} else {
|
||||
GPIO_INTPOLARITY_A &= ~gpios;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Gets the masked interrupt status
|
||||
|
||||
Returns the pin interrupt status masked with the mask set
|
||||
in @ref gpio_int_mask().
|
||||
|
||||
@return The masked pin interrupt status as a bitfield. The bit position of the
|
||||
pin value returned corresponds to the pin number.
|
||||
*/
|
||||
uint16_t gpio_int_status(void)
|
||||
{
|
||||
return GPIO_INTSTAT_A;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Gets the raw unmasked interrupt status
|
||||
|
||||
Returns the raw unmasked interrupt status.
|
||||
|
||||
@return The unmasked pin interrupt status as a bitfield. The bit position of the
|
||||
pin value returned corresponds to the pin number.
|
||||
*/
|
||||
uint16_t gpio_int_raw_status(void)
|
||||
{
|
||||
return GPIO_RAWINTSTAT_A;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Clear the specified pin interrupts
|
||||
|
||||
Clears the specified pin interrupts. Edge-triggered interrupts must be cleared
|
||||
by software.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
*/
|
||||
void gpio_int_clear(uint16_t gpios)
|
||||
{
|
||||
GPIO_INTEOI_A |= gpios;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
42
libopencm3/lib/swm050/pwr.c
Normal file
42
libopencm3/lib/swm050/pwr.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/** @defgroup pwr_file Power/Sleep API
|
||||
* @brief SWM050 Power API.
|
||||
* @ingroup peripheral_apis
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/sysctl.h>
|
||||
#include <libopencm3/swm050/pwr.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Go into sleep mode
|
||||
|
||||
Goes to sleep and wakes up on when GPIO pin 9 is pulled low. Please give
|
||||
yourself enough time to connect the debugger before calling this, in order to
|
||||
not get locked out of the MCU.
|
||||
|
||||
*/
|
||||
void pwr_sleep(void)
|
||||
{
|
||||
SYSCTL_SYS_CFG_2 |= SYSCTL_SYS_CFG_2_SLEEP;
|
||||
}
|
||||
/**@}*/
|
||||
116
libopencm3/lib/swm050/syscon.c
Normal file
116
libopencm3/lib/swm050/syscon.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/** @defgroup syscon_file SYSCON peripheral API
|
||||
* @ingroup peripheral_apis
|
||||
* @brief SWM050 SYSCON API.
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Icenowy Zheng <icenowy@aosc.io>
|
||||
* @author @htmlonly © @endhtmlonly 2019
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Icenowy Zheng <icenowy@aosc.io>
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/syscon.h>
|
||||
#include <libopencm3/swm050/gpio.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Select the alternative function of a Group of Pins
|
||||
|
||||
Select the alternative function of one or more pins of GPIO.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
@param[in] af_en Whether alternative function is selected
|
||||
*/
|
||||
void syscon_sel_af(uint16_t gpios, bool af_en)
|
||||
{
|
||||
uint32_t masked_reg32;
|
||||
|
||||
if (gpios & GPIO0) {
|
||||
masked_reg32 = SYSCON_PORTA_SEL & (~0x3);
|
||||
SYSCON_PORTA_SEL = masked_reg32 | (af_en ? 0x1 : 0x0);
|
||||
}
|
||||
if (gpios & GPIO1) {
|
||||
masked_reg32 = SYSCON_PORTA_SEL & (~0xc);
|
||||
SYSCON_PORTA_SEL = masked_reg32 | (af_en ? 0x4 : 0x0);
|
||||
}
|
||||
if (gpios & GPIO2) {
|
||||
masked_reg32 = SYSCON_PORTA_SEL & (~0x30);
|
||||
SYSCON_PORTA_SEL = masked_reg32 | (af_en ? 0x10 : 0x0);
|
||||
}
|
||||
if (gpios & GPIO7) {
|
||||
masked_reg32 = SYSCON_PORTA_SEL & (~0xc000);
|
||||
SYSCON_PORTA_SEL = masked_reg32 | (af_en ? 0x4000 : 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Enable the internal pull-up of a Group of Pins
|
||||
|
||||
Enable or disable the internal pull-up of one or more pins of GPIO.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
@param[in] en True to enable pull-up, false to disable.
|
||||
*/
|
||||
void syscon_pullup(uint16_t gpios, bool en)
|
||||
{
|
||||
if (en) {
|
||||
SYSCON_PORTA_PULLUP |= gpios;
|
||||
} else {
|
||||
SYSCON_PORTA_PULLUP &= ~gpios;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Enable the input function of a Group of Pins
|
||||
|
||||
Enable or disable the input function of one or more pins of GPIO. Disabling
|
||||
the input function of pins decreases the power usage of the MCU.
|
||||
|
||||
@param[in] gpios Pin identifiers @ref gpio_pin_id
|
||||
If multiple pins are to be changed, use bitwise OR '|' to separate
|
||||
them.
|
||||
@param[in] en True to enable input function.
|
||||
*/
|
||||
void syscon_input_enable(uint16_t gpios, bool en)
|
||||
{
|
||||
if (en) {
|
||||
SYSCON_PORTA_INEN &= ~gpios;
|
||||
} else {
|
||||
SYSCON_PORTA_INEN |= gpios;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Select the SWD function of GPIO 1/2
|
||||
|
||||
Enable or disable the SWD debugging port at GPIO 1/2. When SWD debugging port
|
||||
is enabled, GPIO and AF of the SWD pins will be both unavailable.
|
||||
|
||||
@param[in] en True to enable SWD.
|
||||
*/
|
||||
void syscon_sel_swd(bool en)
|
||||
{
|
||||
SYSCON_SWD_SEL = en;
|
||||
}
|
||||
/**@}*/
|
||||
454
libopencm3/lib/swm050/timer.c
Normal file
454
libopencm3/lib/swm050/timer.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/** @defgroup timer_file Timer peripheral API
|
||||
* @brief SWM050 Timer API.
|
||||
* @ingroup peripheral_apis
|
||||
* LGPL License Terms @ref lgpl_license
|
||||
* @author @htmlonly © @endhtmlonly 2020
|
||||
* Caleb Szalacinski <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2020 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/timer.h>
|
||||
#include <libopencm3/swm050/sysctl.h>
|
||||
#include <libopencm3/swm050/syscon.h>
|
||||
|
||||
/**
|
||||
* Internal function for timer setup.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param timer_int_en Passed to @ref timer_int_enable()
|
||||
* @param op_mode Passed to @ref timer_operation_mode()
|
||||
* @param edge_mode Passed to @ref timer_edge_mode()
|
||||
* @param loop_mode Passed to @ref timer_loop_mode()
|
||||
* @param clk_src Passed to @ref timer_clock_source()
|
||||
* @param output_mode Passed to @ref timer_output_mode()
|
||||
* @param output_level Passed to @ref timer_output_level()
|
||||
*/
|
||||
static void timer_setup_internal(uint32_t timer,
|
||||
bool timer_int_en,
|
||||
enum timer_operation_modes op_mode,
|
||||
enum timer_edge_modes edge_mode,
|
||||
enum timer_loop_modes loop_mode,
|
||||
enum timer_clk_src clk_src,
|
||||
enum timer_output_modes output_mode,
|
||||
enum timer_level output_level)
|
||||
{
|
||||
timer_enable(timer, false);
|
||||
|
||||
/* Conserve power by shutting off the unneeded clock */
|
||||
timer_clock_enable(timer, (clk_src == TIMER_CLK_INTERNAL));
|
||||
|
||||
timer_loop_mode(timer, loop_mode);
|
||||
timer_output_mode(timer, output_mode);
|
||||
timer_output_level(timer, output_level);
|
||||
timer_clock_source(timer, clk_src);
|
||||
timer_operation_mode(timer, op_mode);
|
||||
timer_edge_mode(timer, edge_mode);
|
||||
timer_int_enable(timer, timer_int_en);
|
||||
timer_int_mask(timer, TIMER_UNMASKED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the timer in counter mode.
|
||||
* @note Call @ref timer_enable() when you are ready to start the timer.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @note If interrupts are enabled here, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param timer_int_en Passed to @ref timer_int_enable()
|
||||
* @param edge_mode Passed to @ref timer_edge_mode()
|
||||
* @param loop_mode Passed to @ref timer_loop_mode()
|
||||
* @param clk_src Passed to @ref timer_clock_source()
|
||||
* @param output_mode Passed to @ref timer_output_mode()
|
||||
* @param output_level Passed to @ref timer_output_level()
|
||||
* @param target Passed to @ref timer_counter_target_value()
|
||||
*/
|
||||
void timer_counter_setup(uint32_t timer,
|
||||
bool timer_int_en,
|
||||
enum timer_edge_modes edge_mode,
|
||||
enum timer_loop_modes loop_mode,
|
||||
enum timer_clk_src clk_src,
|
||||
enum timer_output_modes output_mode,
|
||||
enum timer_level output_level,
|
||||
uint32_t target)
|
||||
{
|
||||
timer_setup_internal(timer, timer_int_en, TIMER_MODE_COUNTER, edge_mode,
|
||||
loop_mode, clk_src, output_mode, output_level);
|
||||
timer_counter_target_value(timer, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the timer in PWM mode.
|
||||
* @note Call @ref timer_enable() when you are ready to start the timer.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @note If interrupts are enabled here, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param timer_int_en Passed to @ref timer_int_enable()
|
||||
* @param edge_mode Passed to @ref timer_edge_mode()
|
||||
* @param clk_src Passed to @ref timer_clock_source()
|
||||
* @param output_level Passed to @ref timer_output_level()
|
||||
* @param period0 Passed to @ref timer_pwm_target_value()
|
||||
* @param period1 Passed to @ref timer_pwm_target_value()
|
||||
*/
|
||||
void timer_pwm_setup(uint32_t timer,
|
||||
bool timer_int_en,
|
||||
enum timer_edge_modes edge_mode,
|
||||
enum timer_clk_src clk_src,
|
||||
enum timer_level output_level,
|
||||
uint16_t period0,
|
||||
uint16_t period1)
|
||||
{
|
||||
timer_setup_internal(timer, timer_int_en, TIMER_MODE_PWM, edge_mode,
|
||||
TIMER_LOOP_MODE, clk_src, TIMER_OUTPUT_NONE,
|
||||
output_level);
|
||||
timer_pwm_target_value(timer, period0, period1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the timer in pulse capture mode.
|
||||
* @note Call @ref timer_enable() when you are ready to start the timer.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @note If interrupts are enabled here, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param timer_int_en Passed to @ref timer_int_enable()
|
||||
* @param edge_mode Passed to @ref timer_edge_mode()
|
||||
* @param loop_mode Passed to @ref timer_loop_mode()
|
||||
*/
|
||||
void timer_pulse_capture_setup(uint32_t timer,
|
||||
bool timer_int_en,
|
||||
enum timer_edge_modes edge_mode,
|
||||
enum timer_loop_modes loop_mode)
|
||||
{
|
||||
timer_setup_internal(timer, timer_int_en, TIMER_MODE_PULSE_CAPTURE,
|
||||
edge_mode, loop_mode, TIMER_CLK_INTERNAL,
|
||||
TIMER_OUTPUT_NONE, TIMER_LEVEL_LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the timer in duty cycle capture mode.
|
||||
* @note Call @ref timer_enable() when you are ready to start the timer.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @note If interrupts are enabled here, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param timer_int_en Passed to @ref timer_int_enable()
|
||||
* @param edge_mode Passed to @ref timer_edge_mode()
|
||||
* @param loop_mode Passed to @ref timer_loop_mode()
|
||||
*/
|
||||
void timer_duty_cycle_capture_setup(uint32_t timer,
|
||||
bool timer_int_en,
|
||||
enum timer_edge_modes edge_mode,
|
||||
enum timer_loop_modes loop_mode)
|
||||
{
|
||||
timer_setup_internal(timer, timer_int_en, TIMER_MODE_DUTY_CYCLE_CAPTURE,
|
||||
edge_mode, loop_mode, TIMER_CLK_INTERNAL,
|
||||
TIMER_OUTPUT_NONE, TIMER_LEVEL_LOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timer clock divider, based off of the 18MHz oscillator
|
||||
* @param div Timer clock divider. Only the 6 least-significant bits are used,
|
||||
* Takes values from 0 to 63 (in reality the possible values are the even
|
||||
* numbers from 2 to 62, as well as the number 1). Anything after the 6
|
||||
* least-significant bits are stripped off of the value. If the value is 0,
|
||||
* it will be treated as a 1. All odd values other than 1 are rounded down
|
||||
* to the closest even value, due to the fact that all odd values are
|
||||
* treated by the register as a 1, which would likely be unexpected. A
|
||||
* value of 0 would also normally be treated as a 2, which would also be
|
||||
* unexpected behavior.
|
||||
*/
|
||||
void timer_clock_div(uint8_t div)
|
||||
{
|
||||
/* If the value is 0 or 1, make it odd, meaning no divide. */
|
||||
/* Otherwise, drop div to the closest even value. */
|
||||
div = (div <= 1) ? 1 : (div & ~0x1);
|
||||
SYSCTL_SYS_CFG_0 = (~TIMER_DIV_MASK & SYSCTL_SYS_CFG_0) | (div << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param en Enable or disable the timer
|
||||
*/
|
||||
void timer_enable(uint32_t timer, bool en)
|
||||
{
|
||||
if (en) {
|
||||
TIMER_CTRL(timer) |= TIMER_CTRL_EN;
|
||||
} else {
|
||||
TIMER_CTRL(timer) &= ~TIMER_CTRL_EN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the timer's internal clock.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param en Enable or disable the internal clock
|
||||
*/
|
||||
void timer_clock_enable(uint32_t timer, bool en)
|
||||
{
|
||||
if (timer == TIMER_SE1) {
|
||||
if (en) {
|
||||
SYSCTL_SYS_CFG_1 |= SYSCTL_SYS_CFG_1_TIMERSE1;
|
||||
} else {
|
||||
SYSCTL_SYS_CFG_1 &= ~SYSCTL_SYS_CFG_1_TIMERSE1;
|
||||
}
|
||||
} else {
|
||||
if (en) {
|
||||
SYSCTL_SYS_CFG_1 |= SYSCTL_SYS_CFG_1_TIMERSE0;
|
||||
} else {
|
||||
SYSCTL_SYS_CFG_1 &= ~SYSCTL_SYS_CFG_1_TIMERSE0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the mode of operation.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param mode The mode of operation @ref timer_operation_modes
|
||||
*/
|
||||
void timer_operation_mode(uint32_t timer, enum timer_operation_modes mode)
|
||||
{
|
||||
uint32_t reg = TIMER_CTRL(timer) & ~(TIMER_CTRL_OUTMOD_MASK << TIMER_CTRL_OUTMOD_SHIFT);
|
||||
TIMER_CTRL(timer) = reg | (mode << TIMER_CTRL_OUTMOD_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the output mode.
|
||||
* Only used in counter mode.
|
||||
* When done counting, the pin can be set to no output,
|
||||
* to invert the current pin level, to set the pin high,
|
||||
* or to set the pin low.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param mode The output mode @ref timer_output_modes
|
||||
*/
|
||||
void timer_output_mode(uint32_t timer, enum timer_output_modes mode)
|
||||
{
|
||||
uint32_t reg = TIMER_CTRL(timer) & ~(TIMER_CTRL_WMOD_MASK << TIMER_CTRL_WMOD_SHIFT);
|
||||
TIMER_CTRL(timer) = reg | (mode << TIMER_CTRL_WMOD_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the initial output level.
|
||||
* Only used in counter and PWM modes.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param level The initial output level @ref timer_level
|
||||
*/
|
||||
void timer_output_level(uint32_t timer, enum timer_level level)
|
||||
{
|
||||
TIMER_OUTPVAL(timer) = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the edge mode.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param mode The edge mode @ref timer_edge_modes
|
||||
*/
|
||||
void timer_edge_mode(uint32_t timer, enum timer_edge_modes mode)
|
||||
{
|
||||
if (mode) {
|
||||
TIMER_CTRL(timer) |= TIMER_CTRL_TMOD;
|
||||
} else {
|
||||
TIMER_CTRL(timer) &= ~TIMER_CTRL_TMOD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the loop mode.
|
||||
* This has no use in PWM mode.
|
||||
* In loop mode with counter mode, the counter will constantly loop.
|
||||
* In loop mode with the capture modes, the values will be captured
|
||||
* again and again. In single mode, these operations happen only once.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param mode The loop mode @ref timer_loop_modes
|
||||
*/
|
||||
void timer_loop_mode(uint32_t timer, enum timer_loop_modes mode)
|
||||
{
|
||||
if (mode) {
|
||||
TIMER_CTRL(timer) |= TIMER_CTRL_LMOD;
|
||||
} else {
|
||||
TIMER_CTRL(timer) &= ~TIMER_CTRL_LMOD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the clock source for the timer.
|
||||
* @note Be sure to set the alternate functions of the timer pins
|
||||
* with @ref syscon_sel_af() and disable SWD on those pins
|
||||
* with @ref syscon_sel_swd() as needed.
|
||||
* @note If not using the internal clock, you can disable it
|
||||
* with @ref timer_clock_enable() for power savings.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param src Select the internal or external clock source @ref timer_clk_src
|
||||
*/
|
||||
void timer_clock_source(uint32_t timer, enum timer_clk_src src)
|
||||
{
|
||||
if (src) {
|
||||
TIMER_CTRL(timer) |= TIMER_CTRL_OSCMOD;
|
||||
} else {
|
||||
TIMER_CTRL(timer) &= ~TIMER_CTRL_OSCMOD;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target values for counter mode.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param target The value to count up to
|
||||
*/
|
||||
void timer_counter_target_value(uint32_t timer, uint32_t target)
|
||||
{
|
||||
TIMER_TARVAL(timer) = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target values for PWM mode.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param period0 length of period 0 in clock cycles. Whether
|
||||
* it is high or low is set in @ref timer_output_level()
|
||||
* @param period1 length of period 1
|
||||
*/
|
||||
void timer_pwm_target_value(uint32_t timer, uint16_t period0, uint16_t period1)
|
||||
{
|
||||
timer_counter_target_value(timer, (period1 << 16) | period0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the interrupt.
|
||||
* In counter mode, when the count has been completed,
|
||||
* an interrupt is generated.
|
||||
* In PWM mode, on a level change, an interupt is generated.
|
||||
* In either capture mode, when a capture is complete,
|
||||
* an interrupt is generated.
|
||||
* @note If interrupts are enabled here, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the timer.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param en Enable or disable the interrupt
|
||||
*/
|
||||
void timer_int_enable(uint32_t timer, bool en)
|
||||
{
|
||||
if (en) {
|
||||
TIMER_INTCTL(timer) |= TIMER_INTCTL_INTEN;
|
||||
} else {
|
||||
TIMER_INTCTL(timer) &= ~TIMER_INTCTL_INTEN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interrupt mask.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @param masked Whether or not to mask the interrupt @ref timer_int_masked
|
||||
*/
|
||||
void timer_int_mask(uint32_t timer, enum timer_int_masked masked)
|
||||
{
|
||||
if (masked) {
|
||||
TIMER_INTCTL(timer) &= ~TIMER_INTCTL_INTMSK;
|
||||
} else {
|
||||
TIMER_INTCTL(timer) |= TIMER_INTCTL_INTMSK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current counter value, and clears the interrupt/interrupt overflow.
|
||||
* If in PWM mode, this is only used for clearing the interrupt.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The current counter value
|
||||
*/
|
||||
uint32_t timer_get_current_value(uint32_t timer)
|
||||
{
|
||||
return TIMER_CURVAL(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cycle width.
|
||||
* Only used in duty cycle capture mode.
|
||||
* @note See the datasheet for more concise diagrams.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The cycle width
|
||||
*/
|
||||
uint32_t timer_get_cycle_width(uint32_t timer)
|
||||
{
|
||||
return TIMER_CAPW(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pulse width in pulse capture mode,
|
||||
* or gets the period width in duty cycle capture mode.
|
||||
* @note See the datasheet for more concise diagrams.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The pulse width
|
||||
*/
|
||||
uint32_t timer_get_pulse_width(uint32_t timer)
|
||||
{
|
||||
return TIMER_CAPLH(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current output period in PWM mode.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The current output period @ref timer_pwm_period
|
||||
*/
|
||||
enum timer_pwm_period timer_get_pwm_period(uint32_t timer)
|
||||
{
|
||||
return TIMER_MOD2LF(timer) & 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interrupt status after masking.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The interrupt status after masking
|
||||
*/
|
||||
bool timer_int_status(uint32_t timer)
|
||||
{
|
||||
return TIMER_INTMSKSTAT(timer) & 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interrupt status before masking.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The interrupt status before masking
|
||||
*/
|
||||
bool timer_int_raw_status(uint32_t timer)
|
||||
{
|
||||
return TIMER_INTSTAT(timer) & 0x1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interrupt overflow status.
|
||||
* Overflow will occur if the interrupt has not been cleared when a second
|
||||
* interrupt happens.
|
||||
* @param timer Select timer @ref timer_select
|
||||
* @return The interrupt overflow status
|
||||
*/
|
||||
bool timer_int_overflow_status(uint32_t timer)
|
||||
{
|
||||
return TIMER_INTFLAG(timer) & 0x1;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
160
libopencm3/lib/swm050/wdt.c
Normal file
160
libopencm3/lib/swm050/wdt.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/** @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 <contact@skiboy.net>
|
||||
*/
|
||||
/*
|
||||
* This file is part of the libopencm3 project.
|
||||
*
|
||||
* Copyright (C) 2019 Caleb Szalacinski <contact@skiboy.net>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**@{*/
|
||||
#include <libopencm3/swm050/wdt.h>
|
||||
#include <libopencm3/swm050/sysctl.h>
|
||||
|
||||
/**
|
||||
* Sets up the WDT before the call to @ref wdt_enable().
|
||||
* This only prepares the watchdog, it will not start counting until
|
||||
* it is enabled.
|
||||
* @param mode passed to @ref wdt_mode()
|
||||
* @param time1 passed to @ref wdt_set_time()
|
||||
* @param time2 passed to @ref 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.
|
||||
* This actually starts the watchdog, you should have already selected
|
||||
* modes and set timeouts.
|
||||
* If @ref WDT_MODE_INT is used, the interrupt should also be enabled
|
||||
* using the NVIC before enabling the WDT.
|
||||
* @sa wdt_setup
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset 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.
|
||||
* @note Only useful with @ref 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.
|
||||
* @note Only useful with @ref 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.
|
||||
* This only enables the clock to the peripheral.
|
||||
* @sa wdt_setup
|
||||
* @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 @ref 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.
|
||||
*
|
||||
* Only the least significant 4 bits are used for both values, eg 0 to 15.
|
||||
*
|
||||
* @param time1 The timer value used in both modes. In @ref WDT_MODE_RESET, this
|
||||
* value counts down to 0 and resets the system. In @ref WDT_MODE_INT, this value
|
||||
* counts down to 0, generates a WDT interrupt, loads time2 into the counter,
|
||||
* and counts down.
|
||||
* @param time2 The timer value used after time1 in mode @ref 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 @ref WDT_MODE_RESET.
|
||||
*/
|
||||
void wdt_set_time(uint8_t time1, uint8_t time2)
|
||||
{
|
||||
WDT_TORR = ((0xF & time1) << 4) | (0xF & time2);
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
Reference in New Issue
Block a user