You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

365 lines
9.3 KiB
C

/**
* \file
*
* \brief XMEGA architecture specific IOPORT service implementation header file.
*
* Copyright (c) 2012-2016 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
*
*/
/*
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef IOPORT_XMEGA_H
#define IOPORT_XMEGA_H
#define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 8 + (pin))
#define IOPORT_BASE_ADDRESS 0x600
#define IOPORT_PORT_OFFSET 0x20
/** \name IOPORT port numbers */
/** @{ */
#if !XMEGA_B3
# define IOPORT_PORTA 0
#endif
#define IOPORT_PORTB 1
#define IOPORT_PORTC 2
#define IOPORT_PORTD 3
#if !XMEGA_B3
# define IOPORT_PORTE 4
#endif
#if XMEGA_A1 || XMEGA_A1U || XMEGA_A3 || XMEGA_A3U || XMEGA_A3B || XMEGA_A3BU || \
XMEGA_C3 || XMEGA_D3
# define IOPORT_PORTF 5
#endif
#if XMEGA_B1 || XMEGA_B3
# define IOPORT_PORTG 6
#endif
#if XMEGA_A1 || XMEGA_A1U
# define IOPORT_PORTH 7
# define IOPORT_PORTJ 8
# define IOPORT_PORTK 9
#endif
#if XMEGA_B1 || XMEGA_B3
# define IOPORT_PORTM 11
#endif
#if XMEGA_A1 || XMEGA_A1U
# define IOPORT_PORTQ 14
#endif
#define IOPORT_PORTR 15
/** @} */
/**
* \weakgroup ioport_group
* \section ioport_modes IOPORT Modes
*
* For details on these please see the XMEGA Manual.
*
* @{
*/
/** \name IOPORT Mode bit definitions */
/** @{ */
#define IOPORT_MODE_TOTEM (0x00 << 3) /*!< Totem-pole */
#define IOPORT_MODE_BUSKEEPER (0x01 << 3) /*!< Buskeeper */
#define IOPORT_MODE_PULLDOWN (0x02 << 3) /*!< Pull-down */
#define IOPORT_MODE_PULLUP (0x03 << 3) /*!< Pull-up */
#define IOPORT_MODE_WIREDOR (0x04 << 3) /*!< Wired OR */
#define IOPORT_MODE_WIREDAND (0x05 << 3) /*!< Wired AND */
#define IOPORT_MODE_WIREDORPULL (0x06 << 3) /*!< Wired OR with pull-down */
#define IOPORT_MODE_WIREDANDPULL (0x07 << 3) /*!< Wired AND with pull-up */
#define IOPORT_MODE_INVERT_PIN (0x01 << 6) /*!< Invert output and input */
#define IOPORT_MODE_SLEW_RATE_LIMIT (0x01 << 7) /*!< Slew rate limiting */
/** @} */
/** @} */
typedef uint8_t ioport_mode_t;
typedef uint8_t ioport_pin_t;
typedef uint8_t ioport_port_t;
typedef uint8_t ioport_port_mask_t;
__always_inline static ioport_port_t arch_ioport_pin_to_port_id(ioport_pin_t pin)
{
return pin >> 3;
}
__always_inline static PORT_t *arch_ioport_port_to_base(ioport_port_t port)
{
return (PORT_t *)((uintptr_t)IOPORT_BASE_ADDRESS +
(port * IOPORT_PORT_OFFSET));
}
__always_inline static PORT_t *arch_ioport_pin_to_base(ioport_pin_t pin)
{
return arch_ioport_port_to_base(arch_ioport_pin_to_port_id(pin));
}
__always_inline static ioport_port_mask_t arch_ioport_pin_to_mask(
ioport_pin_t pin)
{
return 1U << (pin & 0x07);
}
__always_inline static ioport_port_mask_t arch_ioport_pin_to_index(
ioport_pin_t pin)
{
return (pin & 0x07);
}
__always_inline static void arch_ioport_init(void)
{
}
__always_inline static void arch_ioport_enable_port(ioport_port_t port,
ioport_port_mask_t mask)
{
PORT_t *base = arch_ioport_port_to_base(port);
volatile uint8_t *pin_ctrl = &base->PIN0CTRL;
uint8_t flags = cpu_irq_save();
for (uint8_t i = 0; i < 8; i++) {
if (mask & arch_ioport_pin_to_mask(i)) {
pin_ctrl[i] &= ~PORT_ISC_gm;
}
}
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_enable_pin(ioport_pin_t pin)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
volatile uint8_t *pin_ctrl
= (&base->PIN0CTRL + arch_ioport_pin_to_index(pin));
uint8_t flags = cpu_irq_save();
*pin_ctrl &= ~PORT_ISC_gm;
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_disable_port(ioport_port_t port,
ioport_port_mask_t mask)
{
PORT_t *base = arch_ioport_port_to_base(port);
volatile uint8_t *pin_ctrl = &base->PIN0CTRL;
uint8_t flags = cpu_irq_save();
for (uint8_t i = 0; i < 8; i++) {
if (mask & arch_ioport_pin_to_mask(i)) {
pin_ctrl[i] |= PORT_ISC_INPUT_DISABLE_gc;
}
}
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_disable_pin(ioport_pin_t pin)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
volatile uint8_t *pin_ctrl
= (&base->PIN0CTRL + arch_ioport_pin_to_index(pin));
uint8_t flags = cpu_irq_save();
*pin_ctrl |= PORT_ISC_INPUT_DISABLE_gc;
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_set_port_mode(ioport_port_t port,
ioport_port_mask_t mask, ioport_mode_t mode)
{
PORT_t *base = arch_ioport_port_to_base(port);
volatile uint8_t *pin_ctrl = &base->PIN0CTRL;
uint8_t new_mode_bits = (mode & ~PORT_ISC_gm);
uint8_t flags = cpu_irq_save();
for (uint8_t i = 0; i < 8; i++) {
if (mask & arch_ioport_pin_to_mask(i)) {
pin_ctrl[i]
= (pin_ctrl[i] &
PORT_ISC_gm) | new_mode_bits;
}
}
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_set_pin_mode(ioport_pin_t pin,
ioport_mode_t mode)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
volatile uint8_t *pin_ctrl
= (&base->PIN0CTRL + arch_ioport_pin_to_index(pin));
uint8_t flags = cpu_irq_save();
*pin_ctrl &= PORT_ISC_gm;
*pin_ctrl |= mode;
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_set_port_dir(ioport_port_t port,
ioport_port_mask_t mask, enum ioport_direction dir)
{
PORT_t *base = arch_ioport_port_to_base(port);
if (dir == IOPORT_DIR_OUTPUT) {
base->DIRSET = mask;
} else if (dir == IOPORT_DIR_INPUT) {
base->DIRCLR = mask;
}
}
__always_inline static void arch_ioport_set_pin_dir(ioport_pin_t pin,
enum ioport_direction dir)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
if (dir == IOPORT_DIR_OUTPUT) {
base->DIRSET = arch_ioport_pin_to_mask(pin);
} else if (dir == IOPORT_DIR_INPUT) {
base->DIRCLR = arch_ioport_pin_to_mask(pin);
}
}
__always_inline static void arch_ioport_set_pin_level(ioport_pin_t pin,
bool level)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
if (level) {
base->OUTSET = arch_ioport_pin_to_mask(pin);
} else {
base->OUTCLR = arch_ioport_pin_to_mask(pin);
}
}
__always_inline static void arch_ioport_set_port_level(ioport_port_t port,
ioport_port_mask_t mask, enum ioport_value level)
{
PORT_t *base = arch_ioport_port_to_base(port);
if (level) {
base->OUTSET |= mask;
base->OUTCLR &= ~mask;
} else {
base->OUTSET &= ~mask;
base->OUTCLR |= mask;
}
}
__always_inline static bool arch_ioport_get_pin_level(ioport_pin_t pin)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
return base->IN & arch_ioport_pin_to_mask(pin);
}
__always_inline static ioport_port_mask_t arch_ioport_get_port_level(
ioport_port_t port, ioport_port_mask_t mask)
{
PORT_t *base = arch_ioport_port_to_base(port);
return base->IN & mask;
}
__always_inline static void arch_ioport_toggle_pin_level(ioport_pin_t pin)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
base->OUTTGL = arch_ioport_pin_to_mask(pin);
}
__always_inline static void arch_ioport_toggle_port_level(ioport_port_t port,
ioport_port_mask_t mask)
{
PORT_t *base = arch_ioport_port_to_base(port);
base->OUTTGL = mask;
}
__always_inline static void arch_ioport_set_pin_sense_mode(ioport_pin_t pin,
enum ioport_sense pin_sense)
{
PORT_t *base = arch_ioport_pin_to_base(pin);
volatile uint8_t *pin_ctrl
= (&base->PIN0CTRL + arch_ioport_pin_to_index(pin));
uint8_t flags = cpu_irq_save();
*pin_ctrl &= ~PORT_ISC_gm;
*pin_ctrl |= (pin_sense & PORT_ISC_gm);
cpu_irq_restore(flags);
}
__always_inline static void arch_ioport_set_port_sense_mode(ioport_port_t port,
ioport_port_mask_t mask, enum ioport_sense pin_sense)
{
PORT_t *base = arch_ioport_port_to_base(port);
volatile uint8_t *pin_ctrl = &base->PIN0CTRL;
uint8_t new_sense_bits = (pin_sense & PORT_ISC_gm);
uint8_t flags = cpu_irq_save();
for (uint8_t i = 0; i < 8; i++) {
if (mask & arch_ioport_pin_to_mask(i)) {
pin_ctrl[i]
= (pin_ctrl[i] &
~PORT_ISC_gm) | new_sense_bits;
}
}
cpu_irq_restore(flags);
}
#endif /* IOPORT_XMEGA_H */