kopia lustrzana https://github.com/bristol-seds/pico-tracker
308 wiersze
9.9 KiB
C
308 wiersze
9.9 KiB
C
|
/**
|
||
|
* SAM D20/D21/R21 GPIO Port Driver
|
||
|
*
|
||
|
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
|
||
|
*
|
||
|
* \asf_license_start
|
||
|
*
|
||
|
* \page License
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are met:
|
||
|
*
|
||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer.
|
||
|
*
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||
|
* this list of conditions and the following disclaimer in the documentation
|
||
|
* and/or other materials provided with the distribution.
|
||
|
*
|
||
|
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||
|
* from this software without specific prior written permission.
|
||
|
*
|
||
|
* 4. This software may only be redistributed and used in connection with an
|
||
|
* Atmel microcontroller product.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||
|
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
* \asf_license_stop
|
||
|
*
|
||
|
*/
|
||
|
#ifndef PORT_H_INCLUDED
|
||
|
#define PORT_H_INCLUDED
|
||
|
|
||
|
/**
|
||
|
* Port Driver (PORT)
|
||
|
*
|
||
|
* This driver for SAM D20/D21/R21 devices provides an interface for
|
||
|
* the configuration and management of the device's General Purpose
|
||
|
* Input/Output (GPIO) pin functionality, for manual pin state reading
|
||
|
* and writing.
|
||
|
*
|
||
|
* The following peripherals are used by this module:
|
||
|
*
|
||
|
* - PORT (GPIO Management)
|
||
|
*
|
||
|
* Module Overview
|
||
|
*
|
||
|
* The device GPIO (PORT) module provides an interface between the
|
||
|
* user application logic and external hardware peripherals, when
|
||
|
* general pin state manipulation is required. This driver provides an
|
||
|
* easy-to-use interface to the physical pin input samplers and output
|
||
|
* drivers, so that pins can be read from or written to for general
|
||
|
* purpose external hardware control.
|
||
|
*
|
||
|
* Physical and Logical GPIO Pins
|
||
|
*
|
||
|
* SAM D20/D21/R21 devices use two naming conventions for the I/O pins
|
||
|
* in the device; one physical, and one logical. Each physical pin on
|
||
|
* a device package is assigned both a physical port and pin
|
||
|
* identifier (e.g. "PORTA.0") as well as a monotonically incrementing
|
||
|
* logical GPIO number (e.g. "GPIO0"). While the former is used to map
|
||
|
* physical pins to their physical internal device module
|
||
|
* counterparts, for simplicity the design of this driver uses the
|
||
|
* logical GPIO numbers instead.
|
||
|
*
|
||
|
* Special Considerations
|
||
|
*
|
||
|
* The SAM D20/D21/R21 port pin input sampler can be disabled when the pin is configured
|
||
|
* in pure output mode to save power; reading the pin state of a pin configured
|
||
|
* in output-only mode will read the logical output state that was last set.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "system/pinmux.h"
|
||
|
|
||
|
/** Convenience definition for GPIO module group A on the device (if
|
||
|
* available). */
|
||
|
#if (PORT_GROUPS > 0)
|
||
|
# define PORTA PORT->Group[0]
|
||
|
#endif
|
||
|
#if (PORT_GROUPS > 1)
|
||
|
/** Convenience definition for GPIO module group B on the device (if
|
||
|
* available). */
|
||
|
# define PORTB PORT->Group[1]
|
||
|
#endif
|
||
|
#if (PORT_GROUPS > 2)
|
||
|
/** Convenience definition for GPIO module group C on the device (if
|
||
|
* available). */
|
||
|
# define PORTC PORT->Group[2]
|
||
|
#endif
|
||
|
#if (PORT_GROUPS > 3)
|
||
|
/** Convenience definition for GPIO module group D on the device (if
|
||
|
* available). */
|
||
|
# define PORTD PORT->Group[3]
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* Enum for the possible pin direction settings of the port pin configuration
|
||
|
* structure, to indicate the direction the pin should use.
|
||
|
*/
|
||
|
enum port_pin_dir {
|
||
|
/** The pin's input buffer should be enabled, so that the pin state can
|
||
|
* be read. */
|
||
|
PORT_PIN_DIR_INPUT = SYSTEM_PINMUX_PIN_DIR_INPUT,
|
||
|
/** The pin's output buffer should be enabled, so that the pin state can
|
||
|
* be set. */
|
||
|
PORT_PIN_DIR_OUTPUT = SYSTEM_PINMUX_PIN_DIR_OUTPUT,
|
||
|
/** The pin's output and input buffers should be enabled, so that the pin
|
||
|
* state can be set and read back. */
|
||
|
PORT_PIN_DIR_OUTPUT_WTH_READBACK = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Enum for the possible pin pull settings of the port pin configuration
|
||
|
* structure, to indicate the type of logic level pull the pin should use.
|
||
|
*/
|
||
|
enum port_pin_pull {
|
||
|
/** No logical pull should be applied to the pin. */
|
||
|
PORT_PIN_PULL_NONE = SYSTEM_PINMUX_PIN_PULL_NONE,
|
||
|
/** Pin should be pulled up when idle. */
|
||
|
PORT_PIN_PULL_UP = SYSTEM_PINMUX_PIN_PULL_UP,
|
||
|
/** Pin should be pulled down when idle. */
|
||
|
PORT_PIN_PULL_DOWN = SYSTEM_PINMUX_PIN_PULL_DOWN,
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Retrieves the PORT module group instance from a given GPIO pin number.
|
||
|
*
|
||
|
* Retrieves the PORT module group instance associated with a given
|
||
|
* logical GPIO pin number.
|
||
|
*
|
||
|
* \param[in] gpio_pin Index of the GPIO pin to convert.
|
||
|
*
|
||
|
* \return Base address of the associated PORT module.
|
||
|
*/
|
||
|
static inline PortGroup* port_get_group_from_gpio_pin(const uint8_t gpio_pin)
|
||
|
{
|
||
|
return system_pinmux_get_group_from_gpio_pin(gpio_pin);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieves the state of a group of port pins that are configured as inputs.
|
||
|
*
|
||
|
* Reads the current logic level of a port module's pins and returns
|
||
|
* the current levels as a bitmask.
|
||
|
*
|
||
|
* \param[in] port Base of the PORT module to read from.
|
||
|
* \param[in] mask Mask of the port pin(s) to read.
|
||
|
*
|
||
|
* \return Status of the port pin(s) input buffers.
|
||
|
*/
|
||
|
static inline uint32_t port_group_get_input_level(const PortGroup *const port,
|
||
|
const uint32_t mask)
|
||
|
{
|
||
|
/* Sanity check arguments */
|
||
|
assert(port);
|
||
|
|
||
|
return (port->IN.reg & mask);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieves the state of a group of port pins that are configured as outputs.
|
||
|
*
|
||
|
* Reads the current logical output level of a port module's pins and
|
||
|
* returns the current levels as a bitmask.
|
||
|
*
|
||
|
* \param[in] port Base of the PORT module to read from.
|
||
|
* \param[in] mask Mask of the port pin(s) to read.
|
||
|
*
|
||
|
* \return Status of the port pin(s) output buffers.
|
||
|
*/
|
||
|
static inline uint32_t port_group_get_output_level(const PortGroup *const port,
|
||
|
const uint32_t mask)
|
||
|
{
|
||
|
/* Sanity check arguments */
|
||
|
assert(port);
|
||
|
|
||
|
return (port->OUT.reg & mask);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the state of a group of port pins that are configured as outputs.
|
||
|
*
|
||
|
* \param[out] port Base of the PORT module to write to.
|
||
|
* \param[in] mask Mask of the port pin(s) to change.
|
||
|
* \param[in] level_mask Mask of the port level(s) to set.
|
||
|
*/
|
||
|
static inline void port_group_set_output_level(PortGroup *const port,
|
||
|
const uint32_t mask,
|
||
|
const uint32_t level_mask)
|
||
|
{
|
||
|
/* Sanity check arguments */
|
||
|
assert(port);
|
||
|
|
||
|
port->OUTSET.reg = (mask & level_mask);
|
||
|
port->OUTCLR.reg = (mask & ~level_mask);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Toggles the state of a group of port pins that are configured as an outputs.
|
||
|
*
|
||
|
* \param[out] port Base of the PORT module to write to.
|
||
|
* \param[in] mask Mask of the port pin(s) to toggle.
|
||
|
*/
|
||
|
static inline void port_group_toggle_output_level(PortGroup *const port,
|
||
|
const uint32_t mask)
|
||
|
{
|
||
|
/* Sanity check arguments */
|
||
|
assert(port);
|
||
|
|
||
|
port->OUTTGL.reg = mask;
|
||
|
}
|
||
|
|
||
|
void port_pin_set_config(const uint8_t gpio_pin,
|
||
|
enum port_pin_dir direction,
|
||
|
enum port_pin_pull input_pull,
|
||
|
bool powersave);
|
||
|
void port_pin_set_config_default(const uint8_t gpio_pin);
|
||
|
|
||
|
|
||
|
void port_group_set_config(PortGroup *const port,
|
||
|
const uint32_t mask,
|
||
|
enum port_pin_dir direction,
|
||
|
enum port_pin_pull input_pull,
|
||
|
bool powersave);
|
||
|
void port_group_set_config_default(PortGroup *const port,
|
||
|
const uint32_t mask);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Reads the current logic level of a port pin and returns the current
|
||
|
* level as a boolean value.
|
||
|
*
|
||
|
* \param[in] gpio_pin Index of the GPIO pin to read.
|
||
|
*
|
||
|
* \return Status of the port pin's input buffer.
|
||
|
*/
|
||
|
static inline bool port_pin_get_input_level(const uint8_t gpio_pin)
|
||
|
{
|
||
|
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
|
||
|
uint32_t pin_mask = (1UL << (gpio_pin % 32));
|
||
|
|
||
|
return (port_base->IN.reg & pin_mask);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads the current logical output level of a port pin and returns the current
|
||
|
* level as a boolean value.
|
||
|
*
|
||
|
* \param[in] gpio_pin Index of the GPIO pin to read.
|
||
|
*
|
||
|
* \return Status of the port pin's output buffer.
|
||
|
*/
|
||
|
static inline bool port_pin_get_output_level(const uint8_t gpio_pin)
|
||
|
{
|
||
|
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
|
||
|
uint32_t pin_mask = (1UL << (gpio_pin % 32));
|
||
|
|
||
|
return (port_base->OUT.reg & pin_mask);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the current output level of a port pin to a given logic level.
|
||
|
*
|
||
|
* \param[in] gpio_pin Index of the GPIO pin to write to.
|
||
|
* \param[in] level Logical level to set the given pin to.
|
||
|
*/
|
||
|
static inline void port_pin_set_output_level(const uint8_t gpio_pin,
|
||
|
const bool level)
|
||
|
{
|
||
|
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
|
||
|
uint32_t pin_mask = (1UL << (gpio_pin % 32));
|
||
|
|
||
|
/* Set the pin to high or low atomically based on the requested level */
|
||
|
if (level) {
|
||
|
port_base->OUTSET.reg = pin_mask;
|
||
|
} else {
|
||
|
port_base->OUTCLR.reg = pin_mask;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Toggles the current output level of a port pin.
|
||
|
*
|
||
|
* \param[in] gpio_pin Index of the GPIO pin to toggle.
|
||
|
*/
|
||
|
static inline void port_pin_toggle_output_level(const uint8_t gpio_pin)
|
||
|
{
|
||
|
PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin);
|
||
|
uint32_t pin_mask = (1UL << (gpio_pin % 32));
|
||
|
|
||
|
/* Toggle pin output level */
|
||
|
port_base->OUTTGL.reg = pin_mask;
|
||
|
}
|
||
|
|
||
|
#endif
|