/**
* \file
*
* \brief SAM 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 Atmel Support
*/
#ifndef IOPORT_SAM0_H
#define IOPORT_SAM0_H
#include
#define IOPORT_CREATE_PIN(port, pin) ((port) * 32 + (pin))
// Aliases
#if (PORT_GROUPS > 0)
# define IOPORT_PORTA 0
#endif
#if (PORT_GROUPS > 1)
# define IOPORT_PORTB 1
#endif
#if (PORT_GROUPS > 2)
# define IOPORT_PORTC 2
#endif
#if (PORT_GROUPS > 3)
# define IOPORT_PORTD 3
#endif
/**
* \weakgroup ioport_group
* \section ioport_modes IOPORT Modes
*
* For details on these please see the device datasheet.
*
* @{
*/
/** \name IOPORT Mode bit definitions */
/** @{ */
#define IOPORT_MODE_MUX_MASK (0xF << 0) /*!< MUX bits mask */
#define IOPORT_MODE_MUX_BIT0 (1 << 0) /*!< MUX BIT0 mask */
#define IOPORT_MODE_MUX_BIT1 (1 << 1) /*!< MUX BIT1 mask */
#define IOPORT_MODE_MUX_BIT2 (1 << 2) /*!< MUX BIT2 mask */
#define IOPORT_MODE_MUX_BIT3 (1 << 3) /*!< MUX BIT3 mask */
#define IOPORT_MODE_MUX_A (0 << 0) /*!< MUX function A */
#define IOPORT_MODE_MUX_B (1 << 0) /*!< MUX function B */
#define IOPORT_MODE_MUX_C (2 << 0) /*!< MUX function C */
#define IOPORT_MODE_MUX_D (3 << 0) /*!< MUX function D */
#define IOPORT_MODE_MUX_E (4 << 0) /*!< MUX function E */
#define IOPORT_MODE_MUX_F (5 << 0) /*!< MUX function F */
#define IOPORT_MODE_MUX_G (6 << 0) /*!< MUX function G */
#define IOPORT_MODE_MUX_H (7 << 0) /*!< MUX function H */
#define IOPORT_MODE_PULLUP (1 << 4) /*!< Pull-up */
#define IOPORT_MODE_PULLDOWN (1 << 5) /*!< Pull-down */
#define IOPORT_MODE_OPEN_DRAIN (1 << 6) /*!< Open Drain */
#define IOPORT_MODE_DRIVE_STRENGTH (1 << 7) /*!< Extra drive strength */
/** @} */
/** @} */
typedef uint32_t ioport_mode_t;
typedef uint32_t ioport_pin_t;
typedef uint32_t ioport_port_t;
typedef uint32_t ioport_port_mask_t;
inline static ioport_port_t arch_ioport_pin_to_port_id(ioport_pin_t pin)
{
return pin >> 5;
}
inline static PortGroup *arch_ioport_port_to_base(
ioport_port_t port)
{
return &PORT->Group[port];
}
inline static PortGroup *arch_ioport_pin_to_base(ioport_pin_t pin)
{
return arch_ioport_port_to_base(arch_ioport_pin_to_port_id(pin));
}
inline static ioport_port_mask_t arch_ioport_pin_to_mask(ioport_pin_t pin)
{
return 1U << (pin & 0x1F);
}
inline static void arch_ioport_init(void)
{
/* No implementation for SAM0 */
}
inline static void arch_ioport_enable_port(ioport_port_t port,
ioport_port_mask_t mask)
{
volatile PortGroup *base = arch_ioport_port_to_base(port);
for (uint32_t i = 0; i < 32; i++) {
if (mask & (1 << i)) {
base->PINCFG[i].reg &= ~PORT_PINCFG_PMUXEN;
}
}
}
inline static void arch_ioport_disable_port(ioport_port_t port,
ioport_port_mask_t mask)
{
volatile PortGroup *base = arch_ioport_port_to_base(port);
for (uint32_t i = 0; i < 32; i++) {
if (mask & (1 << i)) {
base->PINCFG[i].reg |= PORT_PINCFG_PMUXEN;
}
}
}
inline static void arch_ioport_enable_pin(ioport_pin_t pin)
{
arch_ioport_enable_port(arch_ioport_pin_to_port_id(pin),
arch_ioport_pin_to_mask(pin));
}
inline static void arch_ioport_disable_pin(ioport_pin_t pin)
{
arch_ioport_disable_port(arch_ioport_pin_to_port_id(pin),
arch_ioport_pin_to_mask(pin));
}
inline static void arch_ioport_set_port_mode(ioport_port_t port,
ioport_port_mask_t mask, ioport_mode_t mode)
{
PortGroup *base = arch_ioport_port_to_base(port);
uint32_t config_mask = 0;
uint32_t config_mux = 0;
config_mask |= PORT_WRCONFIG_INEN;
if ((mode & IOPORT_MODE_PULLDOWN) || (mode & IOPORT_MODE_PULLUP)) {
config_mask |= PORT_WRCONFIG_PULLEN;
}
#ifdef PORT_WRCONFIG_ODRAIN
if (mode & IOPORT_MODE_OPEN_DRAIN) {
config_mask |= PORT_WRCONFIG_ODRAIN;
}
#endif
if (mode & IOPORT_MODE_DRIVE_STRENGTH) {
config_mask |= PORT_WRCONFIG_DRVSTR;
}
config_mux = (mode & IOPORT_MODE_MUX_MASK) << PORT_WRCONFIG_PMUX_Pos;
uint32_t lower_pin_mask = (mask & 0xFFFF);
uint32_t upper_pin_mask = (mask >> 16);
base->WRCONFIG.reg =
(lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
config_mask | config_mux |
PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;
base->WRCONFIG.reg =
(upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
config_mask | config_mux |
PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG |
PORT_WRCONFIG_HWSEL;
if (mode & IOPORT_MODE_PULLDOWN) {
base->OUTCLR.reg = mask;
}
else if (mode & IOPORT_MODE_PULLUP) {
base->OUTSET.reg = mask;
}
}
inline static void arch_ioport_set_pin_mode(ioport_pin_t pin,
ioport_mode_t mode)
{
arch_ioport_set_port_mode(arch_ioport_pin_to_port_id(pin),
arch_ioport_pin_to_mask(pin), mode);
}
inline static void arch_ioport_set_port_dir(ioport_port_t port,
ioport_port_mask_t mask, unsigned char dir)
{
if (dir == IOPORT_DIR_OUTPUT) {
arch_ioport_port_to_base(port)->DIRSET.reg = mask;
} else if (dir == IOPORT_DIR_INPUT) {
arch_ioport_port_to_base(port)->DIRCLR.reg = mask;
}
}
inline static void arch_ioport_set_pin_dir(ioport_pin_t pin,
enum ioport_direction dir)
{
PortGroup *base = arch_ioport_pin_to_base(pin);
if (dir == IOPORT_DIR_OUTPUT) {
base->DIRSET.reg = arch_ioport_pin_to_mask(pin);
} else if (dir == IOPORT_DIR_INPUT) {
base->DIRCLR.reg = arch_ioport_pin_to_mask(pin);
}
base->PINCFG[pin].reg |= PORT_PINCFG_INEN;
}
inline static void arch_ioport_set_pin_level(ioport_pin_t pin,
bool level)
{
if (level) {
arch_ioport_pin_to_base(pin)->OUTSET.reg = arch_ioport_pin_to_mask(pin);
} else {
arch_ioport_pin_to_base(pin)->OUTCLR.reg = arch_ioport_pin_to_mask(pin);
}
}
inline static void arch_ioport_set_port_level(ioport_port_t port,
ioport_port_mask_t mask, enum ioport_value level)
{
volatile PortGroup *base = arch_ioport_port_to_base(port);
if (level){
base->OUTSET.reg = mask;
} else {
base->OUTCLR.reg = mask;
}
}
inline static bool arch_ioport_get_pin_level(ioport_pin_t pin)
{
return arch_ioport_pin_to_base(pin)->IN.reg & arch_ioport_pin_to_mask(pin);
}
inline static ioport_port_mask_t arch_ioport_get_port_level(
ioport_port_t port, ioport_port_mask_t mask)
{
return arch_ioport_port_to_base(port)->IN.reg & mask;
}
inline static void arch_ioport_toggle_pin_level(ioport_pin_t pin)
{
arch_ioport_pin_to_base(pin)->OUTTGL.reg = arch_ioport_pin_to_mask(pin);
}
inline static void arch_ioport_toggle_port_level(ioport_port_t port,
ioport_port_mask_t mask)
{
arch_ioport_port_to_base(port)->OUTTGL.reg = mask;
}
inline static void arch_ioport_set_port_sense_mode(ioport_port_t port,
ioport_port_mask_t mask, enum ioport_sense pin_sense)
{
// TODO
Assert(false);
}
inline static void arch_ioport_set_pin_sense_mode(ioport_pin_t pin,
enum ioport_sense pin_sense)
{
arch_ioport_set_port_sense_mode(arch_ioport_pin_to_port_id(pin),
arch_ioport_pin_to_mask(pin), pin_sense);
}
#endif /* IOPORT_SAM0_H */