diff --git a/include/libopencm3/lm4f/uart.h b/include/libopencm3/lm4f/uart.h
index c02f7457..3156b091 100644
--- a/include/libopencm3/lm4f/uart.h
+++ b/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
diff --git a/lib/lm4f/uart.c b/lib/lm4f/uart.c
index abf1c962..e96af0f9 100644
--- a/lib/lm4f/uart.c
+++ b/lib/lm4f/uart.c
@@ -351,29 +351,164 @@ u16 uart_recv_blocking(u32 uart)
*
* \brief Configuring interrupts from the UART
*
+ * 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
+ * @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);
-*/
-
/**
* @}
*/