lm4f: Implement GPIO interrupt control
Implement an API to specifiy the interrupt trigger for GPIO pins, and control interrupts. This completes the GPIO API. Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
This commit is contained in:
committed by
Piotr Esden-Tempski
parent
f53839f33f
commit
4535a4c9b6
@@ -201,6 +201,14 @@ enum gpio_drive_strength {
|
|||||||
GPIO_DRIVE_8MA, /**< 8mA drive */
|
GPIO_DRIVE_8MA, /**< 8mA drive */
|
||||||
GPIO_DRIVE_8MA_SLEW_CTL,/**< 8mA drive with slew rate control */
|
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
|
* Function prototypes
|
||||||
* ---------------------------------------------------------------------------*/
|
* ---------------------------------------------------------------------------*/
|
||||||
@@ -323,10 +331,43 @@ static inline void gpio_port_write(u32 gpioport, u8 data)
|
|||||||
{
|
{
|
||||||
gpio_write(gpioport, GPIO_ALL, 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
|
END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
148
lib/lm4f/gpio.c
148
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 <b>Configuring interrupts from GPIO pins</b>
|
||||||
|
*
|
||||||
|
* 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 <libopencm3/lm4f/nvic.h>
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user