Browse Source

lm4f: Implement UART interrupt control

Add a complete API for controlling the UART interrupts.
Doxygen documentation with inline code examples is also provided in this patch.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
pull/112/merge
Alexandru Gagniuc 12 years ago
committed by Piotr Esden-Tempski
parent
commit
a8fc67d569
  1. 46
      include/libopencm3/lm4f/uart.h
  2. 148
      lib/lm4f/uart.c

46
include/libopencm3/lm4f/uart.h

@ -375,6 +375,32 @@ enum uart_flowctl {
UART_FLOWCTL_RTS_CTS,
};
/**
* \brief UART interrupt masks
*
* These masks can be OR'ed together to specify more than one interrupt. For
* example, (UART_INT_TXIM | UART_INT_TXIM) specifies both Rx and Tx Interrupt.
*/
enum uart_interrupt_flag {
UART_INT_LME5 = UART_IM_LME5IM,
UART_INT_LME1 = UART_IM_LME1IM,
UART_INT_LMSB = UART_IM_LMSBIM,
UART_INT_9BIT = UART_IM_9BITIM,
UART_INT_OE = UART_IM_OEIM,
UART_INT_BE = UART_IM_BEIM,
UART_INT_PE = UART_IM_PEIM,
UART_INT_FE = UART_IM_FEIM,
UART_INT_RT = UART_IM_RTIM,
UART_INT_TX = UART_IM_TXIM,
UART_INT_RX = UART_IM_RXIM,
UART_INT_DSR = UART_IM_DSRIM,
UART_INT_DCD = UART_IM_DCDIM,
UART_INT_CTS = UART_IM_CTSIM,
UART_INT_RI = UART_IM_RIIM,
};
/* =============================================================================
* Function prototypes
* ---------------------------------------------------------------------------*/
@ -403,12 +429,28 @@ void uart_disable_rx_dma(u32 uart);
void uart_enable_tx_dma(u32 uart);
void uart_disable_tx_dma(u32 uart);
void uart_enable_interrupts(u32 uart, enum uart_interrupt_flag ints);
void uart_disable_interrupts(u32 uart, enum uart_interrupt_flag ints);
void uart_enable_rx_interrupt(u32 uart);
void uart_disable_rx_interrupt(u32 uart);
void uart_enable_tx_interrupt(u32 uart);
void uart_disable_tx_interrupt(u32 uart);
bool uart_get_flag(u32 uart, u32 flag);
bool uart_get_interrupt_source(u32 uart, u32 flag);
void uart_clear_interrupt_flag(u32 uart, enum uart_interrupt_flag ints);
/* Let's keep this one inlined. It's designed to be used in ISRs */
/** @ingroup uart_irq
* @{
* \brief Determine if interrupt is generated by the given source
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] source source to check.
*/
static inline
bool uart_is_interrupt_source(u32 uart, enum uart_interrupt_flag source)
{
return UART_MIS(uart) & source;
}
/**@}*/
END_DECLS

148
lib/lm4f/uart.c

@ -351,29 +351,164 @@ u16 uart_recv_blocking(u32 uart)
*
* \brief <b>Configuring interrupts from the UART</b>
*
* To have an event generate an interrupt, its interrupt source must be
* unmasked. This can be achieved with @ref uart_enable_interrupts(). Interrupts
* which are no longer needed can be disabled through
* @ref uart_disable_interrupts().
*
* In order for the interrupt to generate an IRQ and a call to the interrupt
* service routine, the interrupt for the target UART 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 unmasking the desired interrupt, and
* routing the desired UART's interrupt through the NVIC.
* @code{.c}
* // Unmask receive interrupt
* uart_enable_rx_interrupt(UART0);
* // Make sure the interrupt is routed through the NVIC
* nvic_enable_irq(NVIC_UART0_IRQ);
* @endcode
*
* If a more than one interrupt is to be enabled at one time, the interrupts
* can be enabled by a single call to @ref uart_enable_interrupts().
* For example:
* @code{.c}
* // Unmask receive, CTS, and RI, interrupts
* uart_enable_interrupts(UART0, UART_INT_RX | UART_INT_RI | UART_INT_CTS);
* @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 UART ISR. The ISR should query the IRQ flags to determine which
* event caused the interrupt. For this, use @ref uart_is_interrupt_source(),
* with the desired UART_INT flag. After one or more interrupt sources are
* serviced, the IRQ flags must be cleared by the ISR. This can be done with
* @ref uart_clear_interrupt_flag().
*
* A typical UART ISR may look like the following:
* @code{.c}
* void uart0_isr(void)
* {
* u32 serviced_irqs = 0;
*
* // Process individual IRQs
* if (uart_is_interrupt_source(UART0, UART_INT_RX)) {
* process_rx_event();
* serviced_irq |= UART_INT_RX;
* }
* if (uart_is_interrupt_source(UART0, UART_INT_CTS)) {
* process_cts_event();
* serviced_irq |= UART_INT_CTS;
* }
*
* // Clear the interupt flag for the processed IRQs
* uart_clear_interrupt_flag(UART0, serviced_irqs);
* }
* @endcode
*/
/**@{*/
/**
* \brief Enable Specific UART Interrupts
*
* Enable any combination of interrupts. Interrupts may be OR'ed together to
* enable them with one call. For example, to enable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to enable. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_enable_interrupts(u32 uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) |= ints;
}
/**
* \brief Enable Specific UART Interrupts
*
* Disabe any combination of interrupts. Interrupts may be OR'ed together to
* disable them with one call. For example, to disable both the RX and CTS
* interrupts, pass (UART_INT_RX | UART_INT_CTS)
*
* @param[in] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to disable. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_disable_interrupts(u32 uart, enum uart_interrupt_flag ints)
{
UART_IM(uart) &= ~ints;
}
/**
* \brief Enable the UART Receive Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_rx_interrupt(u32 uart)
{
/* TODO: this is just a stub. */
uart_enable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Disable the UART Receive Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_rx_interrupt(u32 uart)
{
/* TODO: this is just a stub. */
uart_disable_interrupts(uart, UART_INT_RX);
}
/**
* \brief Enable the UART Transmit Interrupt.
*
* Note that the NVIC must be enabled and properly configured for the interrupt
* to be routed to the CPU.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_enable_tx_interrupt(u32 uart)
{
/* TODO: this is just a stub. */
uart_enable_interrupts(uart, UART_INT_TX);
}
/**
* \brief Disable the UART Transmit Interrupt.
*
* @param[in] uart UART block register address base @ref uart_reg_base
*/
void uart_disable_tx_interrupt(u32 uart)
{
/* TODO: this is just a stub. */
uart_disable_interrupts(uart, UART_INT_TX);
}
/**
* \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] uart UART block register address base @ref uart_reg_base
* @param[in] ints Interrupts which to clear. Any combination of interrupts may
* be specified by OR'ing then together
*/
void uart_clear_interrupt_flag(u32 uart, enum uart_interrupt_flag ints)
{
UART_ICR(uart) |= ints;
}
/**@}*/
/** @defgroup uart_dma UART DMA control
* @ingroup uart_file
*
@ -403,11 +538,6 @@ void uart_disable_tx_dma(u32 uart)
}
/**@}*/
/*
bool uart_get_flag(u32 uart, u32 flag);
bool uart_get_interrupt_source(u32 uart, u32 flag);
*/
/**
* @}
*/

Loading…
Cancel
Save