From 48c089046fa18e32f44975b78cc156b738175444 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Tue, 1 Jun 2021 18:14:10 +0100 Subject: [PATCH] Add hardware_gpio accessors for Schmitt, slew rate, drive strength (fixes #290) --- src/host/hardware_gpio/gpio.c | 27 +++++- .../hardware_gpio/include/hardware/gpio.h | 23 +++++ src/rp2_common/hardware_gpio/gpio.c | 47 +++++++++++ .../hardware_gpio/include/hardware/gpio.h | 84 +++++++++++++++++++ 4 files changed, 180 insertions(+), 1 deletion(-) diff --git a/src/host/hardware_gpio/gpio.c b/src/host/hardware_gpio/gpio.c index d5f4996f2..497ccff70 100644 --- a/src/host/hardware_gpio/gpio.c +++ b/src/host/hardware_gpio/gpio.c @@ -39,6 +39,31 @@ void gpio_set_oeover(uint gpio, uint value) { } +void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled){ + +} + +bool gpio_is_input_hysteresis_enabled(uint gpio){ + return true; +} + +void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew){ + +} + +enum gpio_slew_rate gpio_get_slew_rate(uint gpio){ + return GPIO_DRIVE_STRENGTH_4MA; +} + +void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive){ + +} + +enum gpio_drive_strength gpio_get_drive_strength(uint gpio){ + return GPIO_SLEW_RATE_FAST; +} + + void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enable) { } @@ -115,4 +140,4 @@ void gpio_set_input_enabled(uint gpio, bool enable) { void gpio_init_mask(uint gpio_mask) { -} \ No newline at end of file +} diff --git a/src/host/hardware_gpio/include/hardware/gpio.h b/src/host/hardware_gpio/include/hardware/gpio.h index d1b14ba9d..a39c97a52 100644 --- a/src/host/hardware_gpio/include/hardware/gpio.h +++ b/src/host/hardware_gpio/include/hardware/gpio.h @@ -27,6 +27,17 @@ enum gpio_function { GPIO_FUNC_NULL = 0xf, }; +enum gpio_slew_rate { + GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled + GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled +}; + +enum gpio_drive_strength { + GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength + GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength + GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength + GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength +}; #define GPIO_OUT 1 #define GPIO_IN 0 @@ -58,6 +69,18 @@ void gpio_set_oeover(uint gpio, uint value); void gpio_set_input_enabled(uint gpio, bool enable); +void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled); + +bool gpio_is_input_hysteresis_enabled(uint gpio); + +void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew); + +enum gpio_slew_rate gpio_get_slew_rate(uint gpio); + +void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive); + +enum gpio_drive_strength gpio_get_drive_strength(uint gpio); + // Configure a GPIO for direct input/output from software void gpio_init(uint gpio); diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c index 2d08c7bc4..d660915a8 100644 --- a/src/rp2_common/hardware_gpio/gpio.c +++ b/src/rp2_common/hardware_gpio/gpio.c @@ -82,6 +82,53 @@ void gpio_set_oeover(uint gpio, uint value) { ); } +void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + if (enabled) + hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); + else + hw_clear_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS); +} + + +bool gpio_is_input_hysteresis_enabled(uint gpio) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_SCHMITT_BITS) != 0; +} + +void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + hw_write_masked(&padsbank0_hw->io[gpio], + (uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB, + PADS_BANK0_GPIO0_SLEWFAST_BITS + ); +} + +enum gpio_slew_rate gpio_get_slew_rate(uint gpio) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + return (enum gpio_slew_rate)((padsbank0_hw->io[gpio] + & PADS_BANK0_GPIO0_SLEWFAST_BITS) + >> PADS_BANK0_GPIO0_SLEWFAST_LSB); +} + + +// Enum encoding should match hardware encoding on RP2040 +static_assert(PADS_BANK0_GPIO0_DRIVE_VALUE_8MA == GPIO_DRIVE_STRENGTH_8MA, ""); +void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + hw_write_masked(&padsbank0_hw->io[gpio], + (uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB, + PADS_BANK0_GPIO0_DRIVE_BITS + ); +} + +enum gpio_drive_strength gpio_get_drive_strength(uint gpio) { + invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS); + return (enum gpio_drive_strength)((padsbank0_hw->io[gpio] + & PADS_BANK0_GPIO0_DRIVE_BITS) + >> PADS_BANK0_GPIO0_DRIVE_LSB); +} + static void gpio_irq_handler(void) { io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl; diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h index 3c261a9e5..74a00a206 100644 --- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h +++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h @@ -140,6 +140,31 @@ enum gpio_override { GPIO_OVERRIDE_HIGH = 3, ///< drive high/enable output }; +/*! \brief Slew rate limiting levels for GPIO outputs + * \ingroup hardware_gpio + * + * Slew rate limiting increases the minimum rise/fall time when a GPIO output + * is lightly loaded, which can help to reduce electromagnetic emissions. + * \sa gpio_set_slew_rate + */ +enum gpio_slew_rate { + GPIO_SLEW_RATE_SLOW = 0, ///< Slew rate limiting enabled + GPIO_SLEW_RATE_FAST = 1 ///< Slew rate limiting disabled +}; + +/*! \brief Drive strength levels for GPIO outputs + * \ingroup hardware_gpio + * + * Drive strength levels for GPIO outputs. + * \sa gpio_set_drive_strength + */ +enum gpio_drive_strength { + GPIO_DRIVE_STRENGTH_2MA = 0, ///< 2 mA nominal drive strength + GPIO_DRIVE_STRENGTH_4MA = 1, ///< 4 mA nominal drive strength + GPIO_DRIVE_STRENGTH_8MA = 2, ///< 8 mA nominal drive strength + GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength +}; + // ---------------------------------------------------------------------------- // Pad Controls + IO Muxing // ---------------------------------------------------------------------------- @@ -246,6 +271,65 @@ void gpio_set_oeover(uint gpio, uint value); */ void gpio_set_input_enabled(uint gpio, bool enabled); +/*! \brief Enable/disable GPIO input hysteresis (Schmitt trigger) + * \ingroup hardware_gpio + * + * Enable or disable the Schmitt trigger hysteresis on a given GPIO. This is + * enabled on all GPIOs by default. Disabling input hysteresis can lead to + * inconsistent readings when the input signal has very long rise or fall + * times, but slightly reduces the GPIO's input delay. + * + * \sa gpio_is_input_hysteresis_enabled + * \param gpio GPIO number + * \param enabled true to enable input hysteresis on specified GPIO + */ +void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled); + +/*! \brief Determine whether input hysteresis is enabled on a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_input_hysteresis_enabled + * \param gpio GPIO number + */ +bool gpio_is_input_hysteresis_enabled(uint gpio); + + +/*! \brief Set slew rate for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_get_slew_rate + * \param gpio GPIO number + * \param slew GPIO output slew rate + */ +void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew); + +/*! \brief Determine current slew rate for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_slew_rate + * \param gpio GPIO number + * \return Current slew rate of that GPIO + */ +enum gpio_slew_rate gpio_get_slew_rate(uint gpio); + +/*! \brief Set drive strength for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_get_drive_strength + * \param gpio GPIO number + * \param drive GPIO output drive strength + */ +void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive); + +/*! \brief Determine current slew rate for a specified GPIO + * \ingroup hardware_gpio + * + * \sa gpio_set_drive_strength + * \param gpio GPIO number + * \return Current drive strength of that GPIO + */ +enum gpio_drive_strength gpio_get_drive_strength(uint gpio); + /*! \brief Enable or disable interrupts for specified GPIO * \ingroup hardware_gpio *