665 lines
23 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_GPIO_H_
#define _HARDWARE_GPIO_H_
#include "pico.h"
#include "hardware/structs/sio.h"
#include "hardware/structs/padsbank0.h"
#include "hardware/structs/iobank0.h"
#ifdef __cplusplus
extern "C" {
#endif
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_GPIO, Enable/disable assertions in the GPIO module, type=bool, default=0, group=hardware_gpio
#ifndef PARAM_ASSERTIONS_ENABLED_GPIO
#define PARAM_ASSERTIONS_ENABLED_GPIO 0
#endif
/** \file gpio.h
* \defgroup hardware_gpio hardware_gpio
*
* General Purpose Input/Output (GPIO) API
*
* RP2040 has 36 multi-functional General Purpose Input / Output (GPIO) pins, divided into two banks. In a typical use case,
* the pins in the QSPI bank (QSPI_SS, QSPI_SCLK and QSPI_SD0 to QSPI_SD3) are used to execute code from an external
* flash device, leaving the User bank (GPIO0 to GPIO29) for the programmer to use. All GPIOs support digital input and
* output, but GPIO26 to GPIO29 can also be used as inputs to the chips Analogue to Digital Converter (ADC). Each GPIO
* can be controlled directly by software running on the processors, or by a number of other functional blocks.
*
* The function allocated to each GPIO is selected by calling the \ref gpio_set_function function. \note Not all functions
* are available on all pins.
*
* Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be selected on
* one _GPIO_ at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the logical OR of these
* GPIO inputs. Please refer to the datasheet for more information on GPIO function select.
*
* ### Function Select Table
*
* GPIO | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9
* -------|----------|-----------|----------|--------|-----|------|------|---------------|----
* 0 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 1 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 2 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 3 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 4 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 5 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 6 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 7 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 8 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 9 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 10 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 11 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 12 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 13 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 14 | SPI1 SCK | UART0 CTS | I2C1 SDA | PWM7 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 15 | SPI1 TX | UART0 RTS | I2C1 SCL | PWM7 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 16 | SPI0 RX | UART0 TX | I2C0 SDA | PWM0 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 17 | SPI0 CSn | UART0 RX | I2C0 SCL | PWM0 B | SIO | PIO0 | PIO1 | | USB VBUS EN
* 18 | SPI0 SCK | UART0 CTS | I2C1 SDA | PWM1 A | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 19 | SPI0 TX | UART0 RTS | I2C1 SCL | PWM1 B | SIO | PIO0 | PIO1 | | USB VBUS DET
* 20 | SPI0 RX | UART1 TX | I2C0 SDA | PWM2 A | SIO | PIO0 | PIO1 | CLOCK GPIN0 | USB VBUS EN
* 21 | SPI0 CSn | UART1 RX | I2C0 SCL | PWM2 B | SIO | PIO0 | PIO1 | CLOCK GPOUT0 | USB OVCUR DET
* 22 | SPI0 SCK | UART1 CTS | I2C1 SDA | PWM3 A | SIO | PIO0 | PIO1 | CLOCK GPIN1 | USB VBUS DET
* 23 | SPI0 TX | UART1 RTS | I2C1 SCL | PWM3 B | SIO | PIO0 | PIO1 | CLOCK GPOUT1 | USB VBUS EN
* 24 | SPI1 RX | UART1 TX | I2C0 SDA | PWM4 A | SIO | PIO0 | PIO1 | CLOCK GPOUT2 | USB OVCUR DET
* 25 | SPI1 CSn | UART1 RX | I2C0 SCL | PWM4 B | SIO | PIO0 | PIO1 | CLOCK GPOUT3 | USB VBUS DET
* 26 | SPI1 SCK | UART1 CTS | I2C1 SDA | PWM5 A | SIO | PIO0 | PIO1 | | USB VBUS EN
* 27 | SPI1 TX | UART1 RTS | I2C1 SCL | PWM5 B | SIO | PIO0 | PIO1 | | USB OVCUR DET
* 28 | SPI1 RX | UART0 TX | I2C0 SDA | PWM6 A | SIO | PIO0 | PIO1 | | USB VBUS DET
* 29 | SPI1 CSn | UART0 RX | I2C0 SCL | PWM6 B | SIO | PIO0 | PIO1 | | USB VBUS EN
*/
/*! \brief GPIO function definitions for use with function select
* \ingroup hardware_gpio
* \brief GPIO function selectors
*
* Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be
* selected on one GPIO at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the logical
* OR of these GPIO inputs.
*
* Please refer to the datsheet for more information on GPIO function selection.
*/
enum gpio_function {
GPIO_FUNC_XIP = 0,
GPIO_FUNC_SPI = 1,
GPIO_FUNC_UART = 2,
GPIO_FUNC_I2C = 3,
GPIO_FUNC_PWM = 4,
GPIO_FUNC_SIO = 5,
GPIO_FUNC_PIO0 = 6,
GPIO_FUNC_PIO1 = 7,
GPIO_FUNC_GPCK = 8,
GPIO_FUNC_USB = 9,
GPIO_FUNC_NULL = 0x1f,
};
#define GPIO_OUT 1
#define GPIO_IN 0
/*! \brief GPIO Interrupt level definitions
* \ingroup hardware_gpio
* \brief GPIO Interrupt levels
*
* An interrupt can be generated for every GPIO pin in 4 scenarios:
*
* * Level High: the GPIO pin is a logical 1
* * Level Low: the GPIO pin is a logical 0
* * Edge High: the GPIO has transitioned from a logical 0 to a logical 1
* * Edge Low: the GPIO has transitioned from a logical 1 to a logical 0
*
* The level interrupts are not latched. This means that if the pin is a logical 1 and the level high interrupt is active, it will
* become inactive as soon as the pin changes to a logical 0. The edge interrupts are stored in the INTR register and can be
* cleared by writing to the INTR register.
*/
enum gpio_irq_level {
GPIO_IRQ_LEVEL_LOW = 0x1u,
GPIO_IRQ_LEVEL_HIGH = 0x2u,
GPIO_IRQ_EDGE_FALL = 0x4u,
GPIO_IRQ_EDGE_RISE = 0x8u,
};
/*! Callback function type for GPIO events
* \ingroup hardware_gpio
*
* \param gpio Which GPIO caused this interrupt
* \param events Which events caused this interrupt. See \ref gpio_set_irq_enabled for details.
* \sa gpio_set_irq_enabled_with_callback()
*/
typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t events);
enum gpio_override {
GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function
GPIO_OVERRIDE_INVERT = 1, ///< invert peripheral signal selected via \ref gpio_set_function
GPIO_OVERRIDE_LOW = 2, ///< drive low/disable output
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
// ----------------------------------------------------------------------------
// Declarations for gpio.c
/*! \brief Select GPIO function
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param fn Which GPIO function select to use from list \ref gpio_function
*/
void gpio_set_function(uint gpio, enum gpio_function fn);
/*! \brief Determine current GPIO function
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return Which GPIO function is currently selected from list \ref gpio_function
*/
enum gpio_function gpio_get_function(uint gpio);
/*! \brief Select up and down pulls on specific GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param up If true set a pull up on the GPIO
* \param down If true set a pull down on the GPIO
*
* \note On the RP2040, setting both pulls enables a "bus keep" function,
* i.e. a weak pull to whatever is current high/low state of GPIO.
*/
void gpio_set_pulls(uint gpio, bool up, bool down);
/*! \brief Set specified GPIO to be pulled up.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_pull_up(uint gpio) {
gpio_set_pulls(gpio, true, false);
}
/*! \brief Determine if the specified GPIO is pulled up.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the GPIO is pulled up
*/
static inline bool gpio_is_pulled_up(uint gpio) {
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_PUE_BITS) != 0;
}
/*! \brief Set specified GPIO to be pulled down.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_pull_down(uint gpio) {
gpio_set_pulls(gpio, false, true);
}
/*! \brief Determine if the specified GPIO is pulled down.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the GPIO is pulled down
*/
static inline bool gpio_is_pulled_down(uint gpio) {
return (padsbank0_hw->io[gpio] & PADS_BANK0_GPIO0_PDE_BITS) != 0;
}
/*! \brief Disable pulls on specified GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
static inline void gpio_disable_pulls(uint gpio) {
gpio_set_pulls(gpio, false, false);
}
/*! \brief Set GPIO IRQ override
* \ingroup hardware_gpio
*
* Optionally invert a GPIO IRQ signal, or drive it high or low
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_irqover(uint gpio, uint value);
/*! \brief Set GPIO output override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_outover(uint gpio, uint value);
/*! \brief Select GPIO input override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_inover(uint gpio, uint value);
/*! \brief Select GPIO output enable override
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value See \ref gpio_override
*/
void gpio_set_oeover(uint gpio, uint value);
/*! \brief Enable GPIO input
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param enabled true to enable input on specified GPIO
*/
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
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* the processor that calls the function.
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt
* \param enabled Enable or disable flag
*
* Events is a bitmask of the following:
*
* bit | interrupt
* ----|----------
* 0 | Low level
* 1 | High level
* 2 | Edge low
* 3 | Edge high
*/
void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled);
/*! \brief Enable interrupts for specified GPIO
* \ingroup hardware_gpio
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* the processor that calls the function.
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt. See \ref gpio_set_irq_enabled for details.
* \param enabled Enable or disable flag
* \param callback user function to call on GPIO irq. Note only one of these can be set per processor.
*
* \note Currently the GPIO parameter is ignored, and this callback will be called for any enabled GPIO IRQ on any pin.
*
*/
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback);
/*! \brief Enable dormant wake up interrupt for specified GPIO
* \ingroup hardware_gpio
*
* This configures IRQs to restart the XOSC or ROSC when they are
* disabled in dormant mode
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt. See \ref gpio_set_irq_enabled for details.
* \param enabled Enable/disable flag
*/
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled);
/*! \brief Acknowledge a GPIO interrupt
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param events Bitmask of events to clear. See \ref gpio_set_irq_enabled for details.
*
*/
void gpio_acknowledge_irq(uint gpio, uint32_t events);
/*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
*
* Clear the output enable (i.e. set to input).
* Clear any output value.
*
* \param gpio GPIO number
*/
void gpio_init(uint gpio);
/*! \brief Resets a GPIO back to the NULL function, i.e. disables it.
* \ingroup hardware_gpio
*
* \param gpio GPIO number
*/
void gpio_deinit(uint gpio);
/*! \brief Initialise multiple GPIOs (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
*
* Clear the output enable (i.e. set to input).
* Clear any output value.
*
* \param gpio_mask Mask with 1 bit per GPIO number to initialize
*/
void gpio_init_mask(uint gpio_mask);
// ----------------------------------------------------------------------------
// Input
// ----------------------------------------------------------------------------
/*! \brief Get state of a single specified GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return Current state of the GPIO. 0 for low, non-zero for high
*/
static inline bool gpio_get(uint gpio) {
return !!((1ul << gpio) & sio_hw->gpio_in);
}
/*! \brief Get raw value of all GPIOs
* \ingroup hardware_gpio
*
* \return Bitmask of raw GPIO values, as bits 0-29
*/
static inline uint32_t gpio_get_all(void) {
return sio_hw->gpio_in;
}
// ----------------------------------------------------------------------------
// Output
// ----------------------------------------------------------------------------
/*! \brief Drive high every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to set, as bits 0-29
*/
static inline void gpio_set_mask(uint32_t mask) {
sio_hw->gpio_set = mask;
}
/*! \brief Drive low every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to clear, as bits 0-29
*/
static inline void gpio_clr_mask(uint32_t mask) {
sio_hw->gpio_clr = mask;
}
/*! \brief Toggle every GPIO appearing in mask
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to toggle, as bits 0-29
*/
static inline void gpio_xor_mask(uint32_t mask) {
sio_hw->gpio_togl = mask;
}
/*! \brief Drive GPIO high/low depending on parameters
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO values to change, as bits 0-29
* \param value Value to set
*
* For each 1 bit in \p mask, drive that pin to the value given by
* corresponding bit in \p value, leaving other pins unchanged.
* Since this uses the TOGL alias, it is concurrency-safe with e.g. an IRQ
* bashing different pins from the same core.
*/
static inline void gpio_put_masked(uint32_t mask, uint32_t value) {
sio_hw->gpio_togl = (sio_hw->gpio_out ^ value) & mask;
}
/*! \brief Drive all pins simultaneously
* \ingroup hardware_gpio
*
* \param value Bitmask of GPIO values to change, as bits 0-29
*/
static inline void gpio_put_all(uint32_t value) {
sio_hw->gpio_out = value;
}
/*! \brief Drive a single GPIO high/low
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param value If false clear the GPIO, otherwise set it.
*/
static inline void gpio_put(uint gpio, bool value) {
uint32_t mask = 1ul << gpio;
if (value)
gpio_set_mask(mask);
else
gpio_clr_mask(mask);
}
/*! \brief Determine whether a GPIO is currently driven high or low
* \ingroup hardware_gpio
*
* This function returns the high/low output level most recently assigned to a
* GPIO via gpio_put() or similar. This is the value that is presented outward
* to the IO muxing, *not* the input level back from the pad (which can be
* read using gpio_get()).
*
* To avoid races, this function must not be used for read-modify-write
* sequences when driving GPIOs -- instead functions like gpio_put() should be
* used to atomically update GPIOs. This accessor is intended for debug use
* only.
*
* \param gpio GPIO number
* \return true if the GPIO output level is high, false if low.
*/
static inline bool gpio_get_out_level(uint gpio) {
return !!(sio_hw->gpio_out & (1u << gpio));
}
// ----------------------------------------------------------------------------
// Direction
// ----------------------------------------------------------------------------
/*! \brief Set a number of GPIOs to output
* \ingroup hardware_gpio
*
* Switch all GPIOs in "mask" to output
*
* \param mask Bitmask of GPIO to set to output, as bits 0-29
*/
static inline void gpio_set_dir_out_masked(uint32_t mask) {
sio_hw->gpio_oe_set = mask;
}
/*! \brief Set a number of GPIOs to input
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO to set to input, as bits 0-29
*/
static inline void gpio_set_dir_in_masked(uint32_t mask) {
sio_hw->gpio_oe_clr = mask;
}
/*! \brief Set multiple GPIO directions
* \ingroup hardware_gpio
*
* \param mask Bitmask of GPIO to set to input, as bits 0-29
* \param value Values to set
*
* For each 1 bit in "mask", switch that pin to the direction given by
* corresponding bit in "value", leaving other pins unchanged.
* E.g. gpio_set_dir_masked(0x3, 0x2); -> set pin 0 to input, pin 1 to output,
* simultaneously.
*/
static inline void gpio_set_dir_masked(uint32_t mask, uint32_t value) {
sio_hw->gpio_oe_togl = (sio_hw->gpio_oe ^ value) & mask;
}
/*! \brief Set direction of all pins simultaneously.
* \ingroup hardware_gpio
*
* \param values individual settings for each gpio; for GPIO N, bit N is 1 for out, 0 for in
*/
static inline void gpio_set_dir_all_bits(uint32_t values) {
sio_hw->gpio_oe = values;
}
/*! \brief Set a single GPIO direction
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \param out true for out, false for in
*/
static inline void gpio_set_dir(uint gpio, bool out) {
uint32_t mask = 1ul << gpio;
if (out)
gpio_set_dir_out_masked(mask);
else
gpio_set_dir_in_masked(mask);
}
/*! \brief Check if a specific GPIO direction is OUT
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return true if the direction for the pin is OUT
*/
static inline bool gpio_is_dir_out(uint gpio) {
return !!(sio_hw->gpio_oe & (1u << (gpio)));
}
/*! \brief Get a specific GPIO direction
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return 1 for out, 0 for in
*/
static inline uint gpio_get_dir(uint gpio) {
return gpio_is_dir_out(gpio); // note GPIO_OUT is 1/true and GPIO_IN is 0/false anyway
}
extern void gpio_debug_pins_init(void);
#ifdef __cplusplus
}
#endif
// PICO_CONFIG: PICO_DEBUG_PIN_BASE, First pin to use for debug output (if enabled), min=0, max=28, default=19, group=hardware_gpio
#ifndef PICO_DEBUG_PIN_BASE
#define PICO_DEBUG_PIN_BASE 19u
#endif
// PICO_CONFIG: PICO_DEBUG_PIN_COUNT, Number of pins to use for debug output (if enabled), min=1, max=28, default=3, group=hardware_gpio
#ifndef PICO_DEBUG_PIN_COUNT
#define PICO_DEBUG_PIN_COUNT 3u
#endif
#ifndef __cplusplus
// note these two macros may only be used once per and only apply per compilation unit (hence the CU_)
#define CU_REGISTER_DEBUG_PINS(...) enum __unused DEBUG_PIN_TYPE { _none = 0, __VA_ARGS__ }; static enum DEBUG_PIN_TYPE __selected_debug_pins;
#define CU_SELECT_DEBUG_PINS(x) static enum DEBUG_PIN_TYPE __selected_debug_pins = (x);
#define DEBUG_PINS_ENABLED(p) (__selected_debug_pins == (p))
#else
#define CU_REGISTER_DEBUG_PINS(p...) \
enum DEBUG_PIN_TYPE { _none = 0, p }; \
template <enum DEBUG_PIN_TYPE> class __debug_pin_settings { \
public: \
static inline bool enabled() { return false; } \
};
#define CU_SELECT_DEBUG_PINS(x) template<> inline bool __debug_pin_settings<x>::enabled() { return true; };
#define DEBUG_PINS_ENABLED(p) (__debug_pin_settings<p>::enabled())
#endif
#define DEBUG_PINS_SET(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_set_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#define DEBUG_PINS_CLR(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_clr_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#define DEBUG_PINS_XOR(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_xor_mask((unsigned)(v)<<PICO_DEBUG_PIN_BASE)
#endif // _GPIO_H_