SWM050: Finishes GPIO, IAP flash, sysclock, sleep/stop, and the sysctl memory map.

Updates the main memory map and the makefile.
Adds the SWM050 to devices.data, so that a linker script can be automatically generated.

Reviewed-by: Karl Palsson <karlp@tweak.net.au>
This commit is contained in:
Caleb Szalacinski
2019-09-21 15:43:50 -05:00
committed by Karl Palsson
parent 1fbfdecb17
commit 3c4ee6f4c0
14 changed files with 760 additions and 89 deletions

View File

@@ -33,8 +33,11 @@ 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
VPATH += ../cm3
include ../Makefile.include

84
lib/swm050/clk.c Normal file
View File

@@ -0,0 +1,84 @@
/** @addtogroup clk_file Clock peripheral API
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @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));
}
}
/**@}*/

96
lib/swm050/flash.c Normal file
View File

@@ -0,0 +1,96 @@
/** @addtogroup flash_file Flash peripheral API
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @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();
}
/**@}*/

View File

@@ -1,10 +1,16 @@
/** @addtogroup gpio_file GPIO peripheral API
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2019
* Icenowy Zheng <icenowy@aosc.io>
* @author @htmlonly &copy; @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
@@ -19,10 +25,8 @@
* 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>
/**@{*/
#include <libopencm3/swm050/gpio.h>
/*---------------------------------------------------------------------------*/
/** @brief Set a Group of Pins
@@ -36,7 +40,7 @@ atomic pin setting.
*/
void gpio_set(uint16_t gpios)
{
GPIO_DATA |= gpios;
GPIO_ADATA |= gpios;
}
/*---------------------------------------------------------------------------*/
@@ -51,7 +55,7 @@ atomic pin setting.
*/
void gpio_clear(uint16_t gpios)
{
GPIO_DATA &= ~gpios;
GPIO_ADATA &= ~gpios;
}
/*---------------------------------------------------------------------------*/
@@ -65,7 +69,7 @@ void gpio_clear(uint16_t gpios)
*/
uint16_t gpio_get(uint16_t gpios)
{
return GPIO_EXT & gpios;
return GPIO_AEXT & gpios;
}
/*---------------------------------------------------------------------------*/
@@ -79,8 +83,8 @@ Toggle one or more pins of GPIO. The non-toggled pins are not affected.
*/
void gpio_toggle(uint16_t gpios)
{
uint32_t curr_status = GPIO_DATA & gpios;
GPIO_DATA = (GPIO_DATA & (~gpios)) | (~curr_status);
uint32_t curr_status = GPIO_ADATA & gpios;
GPIO_ADATA = (GPIO_ADATA & (~gpios)) | (~curr_status);
}
/*---------------------------------------------------------------------------*/
@@ -94,7 +98,7 @@ Set the direction of one or more pins of GPIO to input.
*/
void gpio_input(uint16_t gpios)
{
GPIO_DIR &= ~gpios;
GPIO_ADIR &= ~gpios;
}
/*---------------------------------------------------------------------------*/
@@ -108,90 +112,142 @@ Set the direction of one or more pins of GPIO to output.
*/
void gpio_output(uint16_t gpios)
{
GPIO_DIR |= gpios;
GPIO_ADIR |= gpios;
}
/*---------------------------------------------------------------------------*/
/** @brief Select the alternative function of a Group of Pins
Select the alternative function of one or more pins of GPIO.
/*---------------------------------------------------------------------------*/
/** @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] af_en Whether alternative function is selected
@param[in] en True to enable, false to disable.
*/
void gpio_sel_af(uint16_t gpios, bool af_en)
void gpio_int_enable(uint16_t gpios, bool en)
{
if (gpios & GPIO0) {
GPIO_SEL = (GPIO_SEL & (~0x3)) | (af_en ? 0x1 : 0x0);
}
if (gpios & GPIO1) {
GPIO_SEL = (GPIO_SEL & (~0xc)) | (af_en ? 0x4 : 0x0);
}
if (gpios & GPIO2) {
GPIO_SEL = (GPIO_SEL & (~0x30)) | (af_en ? 0x10 : 0x0);
}
if (gpios & GPIO7) {
GPIO_SEL = (GPIO_SEL & (~0xc000)) | (af_en ? 0x4000 : 0x0);
if (en) {
GPIO_INTEN_A |= gpios;
} else {
GPIO_INTEN_A &= ~gpios;
}
}
/*---------------------------------------------------------------------------*/
/** @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.
/*---------------------------------------------------------------------------*/
/** @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] en Bool. Whether pull-up is enabled
@param[in] masked Pin mask selection @ref gpio_int_masked
Whether to mask or unmask pins.
*/
void gpio_pullup(uint16_t gpios, bool en)
void gpio_int_mask(uint16_t gpios, enum gpio_int_masked masked)
{
if (en) {
GPIO_PULLUP |= gpios;
if (masked) {
GPIO_INTMASK_A |= gpios;
} else {
GPIO_PULLUP &= ~gpios;
GPIO_INTMASK_A &= ~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.
/*---------------------------------------------------------------------------*/
/** @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] en true to enable input function.
@param[in] type Trigger Type @ref gpio_trig_type
Level or edge triggered
*/
void gpio_in_en(uint16_t gpios, bool en)
void gpio_int_type(uint16_t gpios, enum gpio_trig_type type)
{
if (en) {
GPIO_INEN &= ~gpios;
if (type) {
GPIO_INTLEVEL_A |= gpios;
} else {
GPIO_INEN |= gpios;
GPIO_INTLEVEL_A &= ~gpios;
}
}
/*---------------------------------------------------------------------------*/
/** @brief Select the SWD function of GPIO 1/2
/** @brief Sets the interrupt trigger polarity
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.
Sets whether the interrupt is triggered by a high or low level/edge.
@param[in] en true to enable SWD.
@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_sel_swd(bool en)
void gpio_int_pol(uint16_t gpios, enum gpio_pol pol)
{
if (en) {
SWD_SEL = 1;
if (pol) {
GPIO_INTPOLARITY_A |= gpios;
} else {
SWD_SEL = 0;
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;
}
/**@}*/

41
lib/swm050/pwr.c Normal file
View File

@@ -0,0 +1,41 @@
/** @addtogroup pwr_file Power/Sleep API
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @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 |= (1<<4);
}
/**@}*/

115
lib/swm050/syscon.c Normal file
View File

@@ -0,0 +1,115 @@
/** @addtogroup syscon_file SYSCON peripheral API
* @ingroup peripheral_apis
* LGPL License Terms @ref lgpl_license
* @author @htmlonly &copy; @endhtmlonly 2019
* Icenowy Zheng <icenowy@aosc.io>
* @author @htmlonly &copy; @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;
}
/**@}*/