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:
parent
f53839f33f
commit
4535a4c9b6
@ -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
|
||||
|
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;
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user