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>
This commit is contained in:
parent
8112861b60
commit
a8fc67d569
@ -375,6 +375,32 @@ enum uart_flowctl {
|
|||||||
UART_FLOWCTL_RTS_CTS,
|
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
|
* Function prototypes
|
||||||
* ---------------------------------------------------------------------------*/
|
* ---------------------------------------------------------------------------*/
|
||||||
@ -403,12 +429,28 @@ void uart_disable_rx_dma(u32 uart);
|
|||||||
void uart_enable_tx_dma(u32 uart);
|
void uart_enable_tx_dma(u32 uart);
|
||||||
void uart_disable_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_enable_rx_interrupt(u32 uart);
|
||||||
void uart_disable_rx_interrupt(u32 uart);
|
void uart_disable_rx_interrupt(u32 uart);
|
||||||
void uart_enable_tx_interrupt(u32 uart);
|
void uart_enable_tx_interrupt(u32 uart);
|
||||||
void uart_disable_tx_interrupt(u32 uart);
|
void uart_disable_tx_interrupt(u32 uart);
|
||||||
bool uart_get_flag(u32 uart, u32 flag);
|
void uart_clear_interrupt_flag(u32 uart, enum uart_interrupt_flag ints);
|
||||||
bool uart_get_interrupt_source(u32 uart, u32 flag);
|
|
||||||
|
/* 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
|
END_DECLS
|
||||||
|
|
||||||
|
148
lib/lm4f/uart.c
148
lib/lm4f/uart.c
@ -351,29 +351,164 @@ u16 uart_recv_blocking(u32 uart)
|
|||||||
*
|
*
|
||||||
* \brief <b>Configuring interrupts from the UART</b>
|
* \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)
|
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)
|
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)
|
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)
|
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
|
/** @defgroup uart_dma UART DMA control
|
||||||
* @ingroup uart_file
|
* @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…
x
Reference in New Issue
Block a user