Skip to content
Snippets Groups Projects
Unverified Commit ef47dfee authored by Graham Sanderson's avatar Graham Sanderson Committed by GitHub
Browse files

Add new GPIO APIs for adding shared GPIO handlers, and improve docs (#850)

parent 6389927c
Branches
Tags
No related merge requests found
pico_simple_hardware_target(gpio)
target_link_libraries(hardware_gpio INTERFACE hardware_irq)
\ No newline at end of file
......@@ -14,11 +14,13 @@
#include "pico/binary_info.h"
#endif
static gpio_irq_callback_t _callbacks[NUM_CORES];
static gpio_irq_callback_t callbacks[NUM_CORES];
// a 1 bit means the IRQ is handled by a raw IRQ handler
static uint32_t raw_irq_mask[NUM_CORES];
// Get the raw value from the pin, bypassing any muxing or overrides.
int gpio_get_pad(uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_IE_BITS);
return (iobank0_hw->io[gpio].status & IO_BANK0_GPIO0_STATUS_INFROMPAD_BITS)
>> IO_BANK0_GPIO0_STATUS_INFROMPAD_LSB;
......@@ -28,7 +30,7 @@ int gpio_get_pad(uint gpio) {
// Select function for this GPIO, and ensure input/output are enabled at the pad.
// This also clears the input/output/irq override bits.
void gpio_set_function(uint gpio, enum gpio_function fn) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
invalid_params_if(GPIO, ((uint32_t)fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB) & ~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
// Set input enable on, output disable off
hw_write_masked(&padsbank0_hw->io[gpio],
......@@ -42,14 +44,14 @@ void gpio_set_function(uint gpio, enum gpio_function fn) {
/// \end::gpio_set_function[]
enum gpio_function gpio_get_function(uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
return (enum gpio_function) ((iobank0_hw->io[gpio].ctrl & IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS) >> IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB);
}
// Note that, on RP2040, setting both pulls enables a "bus keep" function,
// i.e. weak pull to whatever is current high/low state of GPIO.
void gpio_set_pulls(uint gpio, bool up, bool down) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_write_masked(
&padsbank0_hw->io[gpio],
(bool_to_bit(up) << PADS_BANK0_GPIO0_PUE_LSB) | (bool_to_bit(down) << PADS_BANK0_GPIO0_PDE_LSB),
......@@ -59,7 +61,7 @@ void gpio_set_pulls(uint gpio, bool up, bool down) {
// Direct override for per-GPIO IRQ signal
void gpio_set_irqover(uint gpio, uint value) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_IRQOVER_LSB,
IO_BANK0_GPIO0_CTRL_IRQOVER_BITS
......@@ -68,7 +70,7 @@ void gpio_set_irqover(uint gpio, uint value) {
// Direct overrides for pad controls
void gpio_set_inover(uint gpio, uint value) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_INOVER_LSB,
IO_BANK0_GPIO0_CTRL_INOVER_BITS
......@@ -76,7 +78,7 @@ void gpio_set_inover(uint gpio, uint value) {
}
void gpio_set_outover(uint gpio, uint value) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_OUTOVER_LSB,
IO_BANK0_GPIO0_CTRL_OUTOVER_BITS
......@@ -84,7 +86,7 @@ void gpio_set_outover(uint gpio, uint value) {
}
void gpio_set_oeover(uint gpio, uint value) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
hw_write_masked(&iobank0_hw->io[gpio].ctrl,
value << IO_BANK0_GPIO0_CTRL_OEOVER_LSB,
IO_BANK0_GPIO0_CTRL_OEOVER_BITS
......@@ -92,7 +94,7 @@ 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);
check_gpio_param(gpio);
if (enabled)
hw_set_bits(&padsbank0_hw->io[gpio], PADS_BANK0_GPIO0_SCHMITT_BITS);
else
......@@ -101,12 +103,12 @@ void gpio_set_input_hysteresis_enabled(uint gpio, bool enabled) {
bool gpio_is_input_hysteresis_enabled(uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
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);
check_gpio_param(gpio);
hw_write_masked(&padsbank0_hw->io[gpio],
(uint)slew << PADS_BANK0_GPIO0_SLEWFAST_LSB,
PADS_BANK0_GPIO0_SLEWFAST_BITS
......@@ -114,7 +116,7 @@ void gpio_set_slew_rate(uint gpio, enum gpio_slew_rate slew) {
}
enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
return (enum gpio_slew_rate)((padsbank0_hw->io[gpio]
& PADS_BANK0_GPIO0_SLEWFAST_BITS)
>> PADS_BANK0_GPIO0_SLEWFAST_LSB);
......@@ -124,7 +126,7 @@ enum gpio_slew_rate gpio_get_slew_rate(uint gpio) {
// 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);
check_gpio_param(gpio);
hw_write_masked(&padsbank0_hw->io[gpio],
(uint)drive << PADS_BANK0_GPIO0_DRIVE_LSB,
PADS_BANK0_GPIO0_DRIVE_BITS
......@@ -132,26 +134,29 @@ void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive) {
}
enum gpio_drive_strength gpio_get_drive_strength(uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
check_gpio_param(gpio);
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;
for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio++) {
io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
uint events = (*status_reg >> 4 * (gpio % 8)) & 0xf;
if (events) {
// TODO: If both cores care about this event then the second core won't get the irq?
gpio_acknowledge_irq(gpio, events);
gpio_irq_callback_t callback = _callbacks[get_core_num()];
static void gpio_default_irq_handler(void) {
uint core = get_core_num();
gpio_irq_callback_t callback = callbacks[core];
io_irq_ctrl_hw_t *irq_ctrl_base = core ? &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio+=8) {
uint32_t events8 = irq_ctrl_base->ints[gpio >> 3u];
// note we assume events8 is 0 for non-existent GPIO
for(uint i=gpio;events8 && i<gpio+8;i++) {
uint32_t events = events8 & 0xfu;
if (events && !(raw_irq_mask[core] & (1u << i))) {
gpio_acknowledge_irq(i, events);
if (callback) {
callback(gpio, events);
}
}
events8 >>= 4;
}
}
}
......@@ -178,21 +183,48 @@ void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled) {
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback) {
gpio_set_irq_enabled(gpio, events, enabled);
gpio_set_irq_callback(callback);
if (enabled) irq_set_enabled(IO_IRQ_BANK0, true);
}
void gpio_set_irq_callback(gpio_irq_callback_t callback) {
uint core = get_core_num();
if (callbacks[core]) {
if (!callback) {
irq_remove_handler(IO_IRQ_BANK0, gpio_default_irq_handler);
}
callbacks[core] = callback;
} else if (callback) {
callbacks[core] = callback;
irq_add_shared_handler(IO_IRQ_BANK0, gpio_default_irq_handler, GPIO_IRQ_CALLBACK_ORDER_PRIORITY);
}
}
void gpio_add_raw_irq_handler_with_order_priority_masked(uint gpio_mask, irq_handler_t handler, uint8_t order_priority) {
hard_assert(!(raw_irq_mask[get_core_num()] & gpio_mask)); // should not add multiple handlers for the same event
raw_irq_mask[get_core_num()] |= gpio_mask;
irq_add_shared_handler(IO_IRQ_BANK0, handler, order_priority);
}
void gpio_add_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
gpio_add_raw_irq_handler_with_order_priority_masked(gpio_mask, handler, GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
}
// TODO: Do we want to support a callback per GPIO pin?
// Install IRQ handler
_callbacks[get_core_num()] = callback;
irq_set_exclusive_handler(IO_IRQ_BANK0, gpio_irq_handler);
irq_set_enabled(IO_IRQ_BANK0, true);
void gpio_remove_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler) {
assert(raw_irq_mask[get_core_num()] & gpio_mask); // should not remove handlers that are not added
irq_remove_handler(IO_IRQ_BANK0, handler);
raw_irq_mask[get_core_num()] &= ~gpio_mask;
}
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled) {
check_gpio_param(gpio);
io_irq_ctrl_hw_t *irq_ctrl_base = &iobank0_hw->dormant_wake_irq_ctrl;
_gpio_set_irq_enabled(gpio, events, enabled, irq_ctrl_base);
}
void gpio_acknowledge_irq(uint gpio, uint32_t events) {
iobank0_hw->intr[gpio / 8] = events << 4 * (gpio % 8);
check_gpio_param(gpio);
iobank0_hw->intr[gpio / 8] = events << (4 * (gpio % 8));
}
#define DEBUG_PIN_MASK (((1u << PICO_DEBUG_PIN_COUNT)-1) << PICO_DEBUG_PIN_BASE)
......@@ -222,7 +254,7 @@ void gpio_deinit(uint gpio) {
}
void gpio_init_mask(uint gpio_mask) {
for(uint i=0;i<32;i++) {
for(uint i=0;i<NUM_BANK0_GPIOS;i++) {
if (gpio_mask & 1) {
gpio_init(i);
}
......
......
......@@ -11,6 +11,7 @@
#include "hardware/structs/sio.h"
#include "hardware/structs/padsbank0.h"
#include "hardware/structs/iobank0.h"
#include "hardware/irq.h"
#ifdef __cplusplus
extern "C" {
......@@ -103,7 +104,7 @@ enum gpio_function {
#define GPIO_OUT 1
#define GPIO_IN 0
/*! \brief GPIO Interrupt level definitions
/*! \brief GPIO Interrupt level definitions (GPIO events)
* \ingroup hardware_gpio
* \brief GPIO Interrupt levels
*
......@@ -129,10 +130,11 @@ enum gpio_irq_level {
* \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.
* \param event_mask Which events caused this interrupt. See \ref gpio_irq_level for details.
* \sa gpio_set_irq_enabled_with_callback()
* \sa gpio_set_irq_callback()
*/
typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t events);
typedef void (*gpio_irq_callback_t)(uint gpio, uint32_t event_mask);
enum gpio_override {
GPIO_OVERRIDE_NORMAL = 0, ///< peripheral signal selected via \ref gpio_set_function
......@@ -166,6 +168,10 @@ enum gpio_drive_strength {
GPIO_DRIVE_STRENGTH_12MA = 3 ///< 12 mA nominal drive strength
};
static inline void check_gpio_param(__unused uint gpio) {
invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
}
// ----------------------------------------------------------------------------
// Pad Controls + IO Muxing
// ----------------------------------------------------------------------------
......@@ -347,63 +353,288 @@ void gpio_set_drive_strength(uint gpio, enum gpio_drive_strength drive);
*/
enum gpio_drive_strength gpio_get_drive_strength(uint gpio);
/*! \brief Enable or disable interrupts for specified GPIO
/*! \brief Enable or disable specific interrupt events for specified GPIO
* \ingroup hardware_gpio
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* This function sets which GPIO events cause a GPIO interrupt on the calling core. See
* \ref gpio_set_irq_callback, \ref gpio_set_irq_enabled_with_callback and
* \ref gpio_add_raw_irq_handler to set up a GPIO interrupt handler to handle the events.
*
* \note The IO IRQs are independent per-processor. This configures the interrupt events for
* the processor that calls the function.
*
* \param gpio GPIO number
* \param events Which events will cause an interrupt
* \param event_mask Which events will cause an interrupt
* \param enabled Enable or disable flag
*
* Events is a bitmask of the following:
* Events is a bitmask of the following \ref gpio_irq_level values:
*
* bit | interrupt
* ----|----------
* 0 | Low level
* 1 | High level
* 2 | Edge low
* 3 | Edge high
* bit | constant | interrupt
* ----|----------------------------------------------------------
* 0 | GPIO_IRQ_LEVEL_LOW | Continuously while level is low
* 1 | GPIO_IRQ_LEVEL_HIGH | Continuously while level is high
* 2 | GPIO_IRQ_EDGE_FALL | On each transition from high to low
* 3 | GPIO_IRQ_EDGE_RISE | On each transition from low to high
*
* which are specified in \ref gpio_irq_level
*/
void gpio_set_irq_enabled(uint gpio, uint32_t events, bool enabled);
void gpio_set_irq_enabled(uint gpio, uint32_t event_mask, bool enabled);
// PICO_CONFIG: GPIO_IRQ_CALLBACK_ORDER_PRIORITY, the irq priority order of the default IRQ callback, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY, group=hardware_gpio
#ifndef GPIO_IRQ_CALLBACK_ORDER_PRIORITY
#define GPIO_IRQ_CALLBACK_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_LOWEST_ORDER_PRIORITY
#endif
/*! \brief Enable interrupts for specified GPIO
// PICO_CONFIG: GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, the irq priority order of raw IRQ handlers if the priortiy is not specified, min=0, max=255, default=PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, group=hardware_gpio
#ifndef GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
#define GPIO_RAW_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
#endif
/*! \brief Set the generic callback used for GPIO IRQ events for the current core
* \ingroup hardware_gpio
*
* \note The IO IRQs are independent per-processor. This configures IRQs for
* This function sets the callback used for all GPIO IRQs on the current core that are not explicitly
* hooked via \ref gpio_add_raw_irq_handler or other gpio_add_raw_irq_handler_ functions.
*
* This function is called with the GPIO number and event mask for each of the (not explicitly hooked)
* GPIOs that have events enabled and that are pending (see \ref gpio_get_irq_event_mask).
*
* \note The IO IRQs are independent per-processor. This function affects
* 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.
* \param callback default user function to call on GPIO irq. Note only one of these can be set per processor.
*/
void gpio_set_irq_callback(gpio_irq_callback_t callback);
/*! \brief Convenience function which performs multiple GPIO IRQ related initializations
* \ingroup hardware_gpio
*
* This method is a slightly eclectic mix of initialization, that:
*
* \li Updates whether the specified events for the specified GPIO causes an interrupt on the calling core based
* on the enable flag.
*
* \li Sets the callback handler for the calling core to callback (or clears the handler if the callback is NULL).
*
* \li Enables GPIO IRQs on the current core if enabled is true.
*
* This method is commonly used to perform a one time setup, and following that any additional IRQs/events are enabled
* via \ref gpio_set_irq_enabled. All GPIOs/events added in this way on the same core share the same callback; for multiple
* independent handlers for different GPIOs you should use \ref gpio_add_raw_irq_handler and related functions.
*
* This method is equivalent to:
*
* \note Currently the GPIO parameter is ignored, and this callback will be called for any enabled GPIO IRQ on any pin.
* \code{.c}
* gpio_set_irq_enabled(gpio, event_mask, enabled);
* gpio_set_irq_callback(callback);
* if (enabled) irq_set_enabled(IO_IRQ_BANK0, true);
* \endcode
*
* \note The IO IRQs are independent per-processor. This method affects only the processor that calls the function.
*
* \param gpio GPIO number
* \param event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details.
* \param enabled Enable or disable flag
* \param callback user function to call on GPIO irq. if NULL, the callback is removed
*/
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t events, bool enabled, gpio_irq_callback_t callback);
void gpio_set_irq_enabled_with_callback(uint gpio, uint32_t event_mask, bool enabled, gpio_irq_callback_t callback);
/*! \brief Enable dormant wake up interrupt for specified GPIO
/*! \brief Enable dormant wake up interrupt for specified GPIO and events
* \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 event_mask Which events will cause an interrupt. See \ref gpio_irq_level for details.
* \param enabled Enable/disable flag
*/
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t events, bool enabled);
void gpio_set_dormant_irq_enabled(uint gpio, uint32_t event_mask, bool enabled);
/*! \brief Return the current interrupt status (pending events) for the given GPIO
* \ingroup hardware_gpio
*
* \param gpio GPIO number
* \return Bitmask of events that are currently pending for the GPIO. See \ref gpio_irq_level for details.
* \sa gpio_acknowledge_irq
*/
static inline uint32_t gpio_get_irq_event_mask(uint gpio) {
check_gpio_param(gpio);
io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
&iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio >> 3u];
return (*status_reg >> (4 * (gpio & 7u))) & 0xfu;
}
/*! \brief Acknowledge a GPIO interrupt
/*! \brief Acknowledge a GPIO interrupt for the specified events on the calling core
* \ingroup hardware_gpio
*
* \note This may be called with a mask of any of valid bits specified in \ref gpio_irq_level, however
* it has no effect on \a level sensitive interrupts which remain pending while the GPIO is at the specified
* level. When handling \a level sensitive interrupts, you should generally disable the interrupt (see
* \ref gpio_set_irq_enabled) and then set it up again later once the GPIO level has changed (or to catch
* the opposite level).
*
* \param gpio GPIO number
* \param events Bitmask of events to clear. See \ref gpio_set_irq_enabled for details.
*
* \note For callbacks set with \ref gpio_set_irq_enabled_with_callback, or \ref gpio_set_irq_callback,this function is called automatically.
* \param event_mask Bitmask of events to clear. See \ref gpio_irq_level for details.
*/
void gpio_acknowledge_irq(uint gpio, uint32_t event_mask);
/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order
* relative to the default callback can be controlled via the order_priority parameter (the default callback has the priority
* \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last).
*
* This method adds such an explicit GPIO IRQ handler, and disables the "default" callback for the specified GPIOs.
*
* \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to.
*
* A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
*
* \code{.c}
* void my_irq_handler(void) {
* if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
* gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
* // handle the IRQ
* }
* if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) {
* gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2);
* // handle the IRQ
* }
* }
* \endcode
*
* @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core
* @param handler the handler to add to the list of GPIO IRQ handlers for this core
* @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core.
*/
void gpio_acknowledge_irq(uint gpio, uint32_t events);
void gpio_add_raw_irq_handler_with_order_priority_masked(uint gpio_mask, irq_handler_t handler, uint8_t order_priority);
/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default callback. The order
* relative to the default callback can be controlled via the order_priority parameter(the default callback has the priority
* \ref GPIO_IRQ_CALLBACK_ORDER_PRIORITY which defaults to the lowest priority with the intention of it running last).
*
* This method adds such a callback, and disables the "default" callback for the specified GPIO.
*
* \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to.
*
* A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
*
* \code{.c}
* void my_irq_handler(void) {
* if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
* gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
* // handle the IRQ
* }
* }
* \endcode
*
* @param gpio the GPIO number that will no longer be passed to the default callback for this core
* @param handler the handler to add to the list of GPIO IRQ handlers for this core
* @param order_priority the priority order to determine the relative position of the handler in the list of GPIO IRQ handlers for this core.
*/
static inline void gpio_add_raw_irq_handler_with_order_priority(uint gpio, irq_handler_t handler, uint8_t order_priority) {
check_gpio_param(gpio);
gpio_add_raw_irq_handler_with_order_priority_masked(1u << gpio, handler, order_priority);
}
/*! \brief Adds a raw GPIO IRQ handler for the specified GPIOs on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
*
* This method adds such a callback, and disables the "default" callback for the specified GPIOs.
*
* \note Multiple raw handlers should not be added for the same GPIOs, and this method will assert if you attempt to.
*
* A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
*
* \code{.c}
* void my_irq_handler(void) {
* if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
* gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
* // handle the IRQ
* }
* if (gpio_get_irq_event_mask(my_gpio_num2) & my_gpio_event_mask2) {
* gpio_acknowledge_irq(my_gpio_num2, my_gpio_event_mask2);
* // handle the IRQ
* }
* }
* \endcode
*
* @param gpio_mask a bit mask of the GPIO numbers that will no longer be passed to the default callback for this core
* @param handler the handler to add to the list of GPIO IRQ handlers for this core
*/
void gpio_add_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler);
/*! \brief Adds a raw GPIO IRQ handler for a specific GPIO on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
*
* This method adds such a callback, and disables the "default" callback for the specified GPIO.
*
* \note Multiple raw handlers should not be added for the same GPIO, and this method will assert if you attempt to.
*
* A raw handler should check for whichever GPIOs and events it handles, and acknowledge them itself; it might look something like:
*
* \code{.c}
* void my_irq_handler(void) {
* if (gpio_get_irq_event_mask(my_gpio_num) & my_gpio_event_mask) {
* gpio_acknowledge_irq(my_gpio_num, my_gpio_event_mask);
* // handle the IRQ
* }
* }
* \endcode
*
* @param gpio the GPIO number that will no longer be passed to the default callback for this core
* @param handler the handler to add to the list of GPIO IRQ handlers for this core
*/
static inline void gpio_add_raw_irq_handler(uint gpio, irq_handler_t handler) {
check_gpio_param(gpio);
gpio_add_raw_irq_handler_masked(1u << gpio, handler);
}
/*! \brief Removes a raw GPIO IRQ handler for the specified GPIOs on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
*
* This method removes such a callback, and enables the "default" callback for the specified GPIOs.
*
* @param gpio_mask a bit mask of the GPIO numbers that will now be passed to the default callback for this core
* @param handler the handler to remove from the list of GPIO IRQ handlers for this core
*/
void gpio_remove_raw_irq_handler_masked(uint gpio_mask, irq_handler_t handler);
/*! \brief Removes a raw GPIO IRQ handler for the specified GPIO on the current core
* \ingroup hardware_gpio
*
* In addition to the default mechanism of a single GPIO IRQ event callback per core (see \ref gpio_set_irq_callback),
* it is possible to add explicit GPIO IRQ handlers which are called independent of the default event callback.
*
* This method removes such a callback, and enables the "default" callback for the specified GPIO.
*
* @param gpio the GPIO number that will now be passed to the default callback for this core
* @param handler the handler to remove from the list of GPIO IRQ handlers for this core
*/
static inline void gpio_remove_raw_irq_handler(uint gpio, irq_handler_t handler) {
check_gpio_param(gpio);
gpio_remove_raw_irq_handler_masked(1u << gpio, handler);
}
/*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO)
* \ingroup hardware_gpio
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment