mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/system/pinmux/pinmux.c

Committer:
mbed_official
Date:
2015-07-17
Revision:
592:a274ee790e56
Parent:
579:53297373a894

File content as of revision 592:a274ee790e56:

#include <pinmux.h>

/**
 * \internal
 * Writes out a given configuration of a Port pin configuration to the
 * hardware module.
 *
 * \note If the pin direction is set as an output, the pull-up/pull-down input
 *       configuration setting is ignored.
 *
 * \param[in] port      Base of the PORT module to configure
 * \param[in] pin_mask  Mask of the port pin to configure
 * \param[in] config    Configuration settings for the pin
 */
static void _system_pinmux_config(
    PortGroup *const port,
    const uint32_t pin_mask,
    const struct system_pinmux_config *const config)
{
    Assert(port);
    Assert(config);

    /* Track the configuration bits into a temporary variable before writing */
    uint32_t pin_cfg = 0;

    /* Enabled powersave mode, don't create configuration */
    if (!config->powersave) {
        /* Enable the pin peripheral MUX flag if non-GPIO selected (pinmux will
         * be written later) and store the new MUX mask */
        if (config->mux_position != SYSTEM_PINMUX_GPIO) {
            pin_cfg |= PORT_WRCONFIG_PMUXEN;
            pin_cfg |= (config->mux_position << PORT_WRCONFIG_PMUX_Pos);
        }

        /* Check if the user has requested that the input buffer be enabled */
        if ((config->direction == SYSTEM_PINMUX_PIN_DIR_INPUT) ||
                (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
            /* Enable input buffer flag */
            pin_cfg |= PORT_WRCONFIG_INEN;

            /* Enable pull-up/pull-down control flag if requested */
            if (config->input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) {
                pin_cfg |= PORT_WRCONFIG_PULLEN;
            }

            /* Clear the port DIR bits to disable the output buffer */
            port->DIRCLR.reg = pin_mask;
        }

        /* Check if the user has requested that the output buffer be enabled */
        if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
                (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
            /* Cannot use a pullup if the output driver is enabled,
             * if requested the input buffer can only sample the current
             * output state */
            pin_cfg &= ~PORT_WRCONFIG_PULLEN;
        }
    } else {
        port->DIRCLR.reg = pin_mask;
    }

    /* The Write Configuration register (WRCONFIG) requires the
     * pins to to grouped into two 16-bit half-words - split them out here */
    uint32_t lower_pin_mask = (pin_mask & 0xFFFF);
    uint32_t upper_pin_mask = (pin_mask >> 16);

    /* Configure the lower 16-bits of the port to the desired configuration,
     * including the pin peripheral multiplexer just in case it is enabled */
    port->WRCONFIG.reg
        = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
          pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG;

    /* Configure the upper 16-bits of the port to the desired configuration,
     * including the pin peripheral multiplexer just in case it is enabled */
    port->WRCONFIG.reg
        = (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) |
          pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG |
          PORT_WRCONFIG_HWSEL;

    if(!config->powersave) {
        /* Set the pull-up state once the port pins are configured if one was
         * requested and it does not violate the valid set of port
         * configurations */
        if (pin_cfg & PORT_WRCONFIG_PULLEN) {
            /* Set the OUT register bits to enable the pullup if requested,
             * clear to enable pull-down */
            if (config->input_pull == SYSTEM_PINMUX_PIN_PULL_UP) {
                port->OUTSET.reg = pin_mask;
            } else {
                port->OUTCLR.reg = pin_mask;
            }
        }

        /* Check if the user has requested that the output buffer be enabled */
        if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) ||
                (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) {
            /* Set the port DIR bits to enable the output buffer */
            port->DIRSET.reg = pin_mask;
        }
    }
}

/**
 * \brief Writes a Port pin configuration to the hardware module.
 *
 * Writes out a given configuration of a Port pin configuration to the hardware
 * module.
 *
 * \note If the pin direction is set as an output, the pull-up/pull-down input
 *       configuration setting is ignored.
 *
 * \param[in] gpio_pin  Index of the GPIO pin to configure
 * \param[in] config    Configuration settings for the pin
 */
void system_pinmux_pin_set_config(
    const uint8_t gpio_pin,
    const struct system_pinmux_config *const config)
{
    PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin);
    uint32_t pin_mask = (1UL << (gpio_pin % 32));

    _system_pinmux_config(port, pin_mask, config);
}

/**
 * \brief Writes a Port pin group configuration to the hardware module.
 *
 * Writes out a given configuration of a Port pin group configuration to the
 * hardware module.
 *
 * \note If the pin direction is set as an output, the pull-up/pull-down input
 *       configuration setting is ignored.
 *
 * \param[in] port      Base of the PORT module to configure
 * \param[in] mask      Mask of the port pin(s) to configure
 * \param[in] config    Configuration settings for the pin
 */
void system_pinmux_group_set_config(
    PortGroup *const port,
    const uint32_t mask,
    const struct system_pinmux_config *const config)
{
    Assert(port);

    for (int i = 0; i < 32; i++) {
        if (mask & (1UL << i)) {
            _system_pinmux_config(port, (1UL << i), config);
        }
    }
}

/**
 * \brief Configures the input sampling mode for a group of pins.
 *
 * Configures the input sampling mode for a group of pins, to
 * control when the physical I/O pin value is sampled and
 * stored inside the microcontroller.
 *
 * \param[in] port     Base of the PORT module to configure
 * \param[in] mask     Mask of the port pin(s) to configure
 * \param[in] mode     New pin sampling mode to configure
 */
void system_pinmux_group_set_input_sample_mode(
    PortGroup *const port,
    const uint32_t mask,
    const enum system_pinmux_pin_sample mode)
{
    Assert(port);

    if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) {
        port->CTRL.reg |= mask;
    } else {
        port->CTRL.reg &= ~mask;
    }
}

#ifdef FEATURE_SYSTEM_PINMUX_SLEWRATE_LIMITER
/**
 * \brief Configures the output slew rate mode for a group of pins.
 *
 * Configures the output slew rate mode for a group of pins, to
 * control the speed at which the physical output pin can react to
 * logical changes of the I/O pin value.
 *
 * \param[in] port     Base of the PORT module to configure
 * \param[in] mask     Mask of the port pin(s) to configure
 * \param[in] mode     New pin slew rate mode to configure
 */
void system_pinmux_group_set_output_slew_rate(
    PortGroup *const port,
    const uint32_t mask,
    const enum system_pinmux_pin_slew_rate mode)
{
    Assert(port);

    for (int i = 0; i < 32; i++) {
        if (mask & (1UL << i)) {
            if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) {
                port->PINCFG[i].reg |=  PORT_PINCFG_SLEWLIM;
            } else {
                port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM;
            }
        }
    }
}
#endif

#ifdef FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH
/**
 * \brief Configures the output driver strength mode for a group of pins.
 *
 * Configures the output drive strength for a group of pins, to
 * control the amount of current the pad is able to sink/source.
 *
 * \param[in] port     Base of the PORT module to configure
 * \param[in] mask     Mask of the port pin(s) to configure
 * \param[in] mode     New output driver strength mode to configure
 */
void system_pinmux_group_set_output_strength(
    PortGroup *const port,
    const uint32_t mask,
    const enum system_pinmux_pin_strength mode)
{
    Assert(port);

    for (int i = 0; i < 32; i++) {
        if (mask & (1UL << i)) {
            if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) {
                port->PINCFG[i].reg |=  PORT_PINCFG_DRVSTR;
            } else {
                port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR;
            }
        }
    }
}
#endif

#ifdef FEATURE_SYSTEM_PINMUX_OPEN_DRAIN
/**
 * \brief Configures the output driver mode for a group of pins.
 *
 * Configures the output driver mode for a group of pins, to
 * control the pad behavior.
 *
 * \param[in] port Base of the PORT module to configure
 * \param[in] mask Mask of the port pin(s) to configure
 * \param[in] mode New pad output driver mode to configure
 */
void system_pinmux_group_set_output_drive(
    PortGroup *const port,
    const uint32_t mask,
    const enum system_pinmux_pin_drive mode)
{
    Assert(port);

    for (int i = 0; i < 32; i++) {
        if (mask & (1UL << i)) {
            if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) {
                port->PINCFG[i].reg |= PORT_PINCFG_ODRAIN;
            } else {
                port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN;
            }
        }
    }
}
#endif