diff --git a/include/libopencm3/lm4f/gpio.h b/include/libopencm3/lm4f/gpio.h
index 0a3513ae..491b54b6 100644
--- a/include/libopencm3/lm4f/gpio.h
+++ b/include/libopencm3/lm4f/gpio.h
@@ -201,6 +201,14 @@ enum gpio_drive_strength {
GPIO_DRIVE_8MA, /**< 8mA drive */
GPIO_DRIVE_8MA_SLEW_CTL,/**< 8mA drive with slew rate control */
};
+
+enum gpio_trigger {
+ GPIO_TRIG_LVL_LOW, /**< Level trigger, signal low */
+ GPIO_TRIG_LVL_HIGH, /**< Level trigger, signal high */
+ GPIO_TRIG_EDGE_FALL, /**< Falling edge trigger */
+ GPIO_TRIG_EDGE_RISE, /**< Rising edge trigger*/
+ GPIO_TRIG_EDGE_BOTH, /**< Falling and Rising edges trigger*/
+};
/* =============================================================================
* Function prototypes
* ---------------------------------------------------------------------------*/
@@ -323,10 +331,43 @@ static inline void gpio_port_write(u32 gpioport, u8 data)
{
gpio_write(gpioport, GPIO_ALL, data);
}
-
-
/** @} */
+void gpio_configure_trigger(u32 gpioport, enum gpio_trigger trigger, u8 gpios);
+void gpio_enable_interrupts(u32 gpioport, u8 gpios);
+void gpio_disable_interrupts(u32 gpioport, u8 gpios);
+
+
+/* Let's keep these ones inlined. GPIO. They are designed to be used in ISRs */
+/** @ingroup gpio_irq
+ * @{ */
+/** \brief Determine if interrupt is generated by the given pin
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] srcpins source pin or group of pins to check.
+ */
+static inline bool gpio_is_interrupt_source(u32 gpioport, u8 srcpins)
+{
+ return GPIO_MIS(gpioport) & srcpins;
+}
+
+/**
+ * \brief Mark interrupt as serviced
+ *
+ * After an interrupt is services, its flag must be cleared. If the flag is not
+ * cleared, then execution will jump back to the start of the ISR after the ISR
+ * returns.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together.
+ */
+static inline void gpio_clear_interrupt_flag(u32 gpioport, u8 gpios)
+{
+ GPIO_ICR(gpioport) |= gpios;
+}
+
+/** @} */
END_DECLS
#endif
diff --git a/lib/lm4f/gpio.c b/lib/lm4f/gpio.c
index f69b8562..4e8e4be1 100644
--- a/lib/lm4f/gpio.c
+++ b/lib/lm4f/gpio.c
@@ -442,5 +442,153 @@ void gpio_toggle(u32 gpioport, u8 gpios)
}
/**@}*/
+
+/** @defgroup gpio_irq GPIO Interrupt control
+ * @ingroup gpio_file
+ *
+ * \brief Configuring interrupts from GPIO pins
+ *
+ * GPIO pins can trigger interrupts on either edges or levels. The type of
+ * trigger can be configured with @ref gpio_configure_int_trigger(). To have an
+ * event on the given pin generate an interrupt, its interrupt source must be
+ * unmasked. This can be achieved with @ref gpio_enable_interrupts(). Interrupts
+ * which are no longer needed can be disabled through
+ * @ref gpio_disable_interrupts().
+ *
+ * In order for the interrupt to generate an IRQ and a call to the interrupt
+ * service routine, the interrupt for the GPIO port must be routed through the
+ * NVIC with @ref nvic_enable_irq(). For this last step, the nvic.h header is
+ * needed:
+ * @code{.c}
+ * #include
+ * @endcode
+ *
+ * Enabling an interrupt is as simple as configuring the desired trigger,
+ * unmasking the desired interrupt, and routing the desired GPIO port's
+ * interrupt through the NVIC.
+ * @code{.c}
+ * // Trigger interrupt on each rising edge
+ * gpio_configure_trigger(GPIOF, GPIO_TRIG_EDGE_RISE, GPIO0 | GPIO4);
+ * // Unmask the interrupt on those pins
+ * gpio_enable_interrupts(GPIOF, GPIO0 | GPIO4);
+ * // Enable the interrupt in the NVIC as well
+ * nvic_enable_irq(NVIC_GPIOF_IRQ);
+ * @endcode
+ *
+ * After interrupts are properly enabled and routed through the NVIC, when an
+ * event occurs, the appropriate IRQ flag is set by hardware, and execution
+ * jumps to the GPIO ISR. The ISR should query the IRQ flags to determine which
+ * event caused the interrupt. For this, use @ref gpio_is_interrupt_source(),
+ * with the desired GPIO flag. After one or more interrupt sources are
+ * serviced, the IRQ flags must be cleared by the ISR. This can be done with
+ * @ref gpio_clear_interrupt_flag().
+ *
+ * A typical GPIO ISR may look like the following:
+ * @code{.c}
+ * void gpiof_isr(void)
+ * {
+ * u8 serviced_irqs = 0;
+ *
+ * // Process individual IRQs
+ * if (gpio_is_interrupt_source(GPIOF, GPIO0)) {
+ * process_gpio0_event();
+ * serviced_irq |= GPIO0;
+ * }
+ * if (gpio_is_interrupt_source(GPIOF, GPIO4)) {
+ * process_gpio4_event();
+ * serviced_irq |= GPIO4;
+ * }
+ *
+ * // Clear the interupt flag for the processed IRQs
+ * gpio_clear_interrupt_flag(GPIOF, serviced_irqs);
+ * }
+ * @endcode
+ */
+/**@{*/
+/**
+ * \brief Configure the interrupt trigger on the given GPIO pins
+ *
+ * Sets the Pin direction, analog/digital mode, and pull-up configuration of
+ * or a set of GPIO pins on a given GPIO port.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] trigger Trigger configuration (@ref gpio_trigger) \n
+ * - GPIO_TRIG_LVL_LOW -- Trigger on low level \n
+ * - GPIO_TRIG_LVL_HIGH -- Trigger on high level \n
+ * - GPIO_TRIG_EDGE_FALL -- Trigger on falling edges \n
+ * - GPIO_TRIG_EDGE_RISE -- Trigger on rising edges \n
+ * - GPIO_TRIG_EDGE_BOTH -- Trigger on all edges
+ * @param[in] gpios @ref gpio_pin_id. Any combination of pins may be specified
+ * by OR'ing then together
+ */
+void gpio_configure_trigger(u32 gpioport, enum gpio_trigger trigger, u8 gpios)
+{
+ switch (trigger) {
+ case GPIO_TRIG_LVL_LOW:
+ GPIO_IS(gpioport) |= gpios;
+ GPIO_IEV(gpioport) &= ~gpios;
+ break;
+ case GPIO_TRIG_LVL_HIGH:
+ GPIO_IS(gpioport) |= gpios;
+ GPIO_IEV(gpioport) |= gpios;
+ break;
+ case GPIO_TRIG_EDGE_FALL:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) &= ~gpios;
+ GPIO_IEV(gpioport) &= ~gpios;
+ break;
+ case GPIO_TRIG_EDGE_RISE:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) &= ~gpios;
+ GPIO_IEV(gpioport) |= gpios;
+ break;
+ case GPIO_TRIG_EDGE_BOTH:
+ GPIO_IS(gpioport) &= ~gpios;
+ GPIO_IBE(gpioport) |= gpios;
+ break;
+ default:
+ /* Don't do anything */
+ break;
+ }
+}
+
+/**
+ * \brief Enable interrupts on specified GPIO pins
+ *
+ * Enable interrupts on the specified GPIO pins
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to enable. Any
+ * combination of pins may be specified by OR'ing them
+ * together.
+ */
+void gpio_enable_interrupts(u32 gpioport, u8 gpios)
+{
+ GPIO_IM(gpioport) |= gpios;
+}
+
+/**
+ * \brief Disable interrupts on specified GPIO pins
+ *
+ * Disable interrupts on the specified GPIO pins
+ *
+ * Note that the NVIC must be enabled and properly configured for the interrupt
+ * to be routed to the CPU.
+ *
+ * @param[in] gpioport GPIO block register address base @ref gpio_reg_base
+ * @param[in] gpios @ref gpio_pin_id. Pins whose interrupts to disable. Any
+ * combination of pins may be specified by OR'ing them
+ * together.
+ */
+void gpio_disable_interrupts(u32 gpioport, u8 gpios)
+{
+ GPIO_IM(gpioport) |= gpios;
+}
+
+/**@}*/
+
/**@}*/