📄 lh79520_uart_driver.c
字号:
/***********************************************************************
* $Workfile: lh79520_uart_driver.c $
* $Revision: 1.0 $
* $Author: LiJ $
* $Date: Jul 07 2003 16:40:02 $
*
* Project: LH79520 UART driver
*
* Description:
* This file contains driver support for the UART modules on the
* LH79520.
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh79520/source/lh79520_uart_driver.c-arc $
*
* Rev 1.0 Jul 07 2003 16:40:02 LiJ
* Initial revision.
*
*
*
***********************************************************************
* SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION
* OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE,
* AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES,
* SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE.
*
* SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
* FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A
* SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE
* FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS.
*
* COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC.
* CAMAS, WA
**********************************************************************/
#include "lh79520_iocon.h"
#include "lh79520_rcpc.h"
#include "lh79520_uart_driver.h"
/***********************************************************************
* UART driver private data and types
**********************************************************************/
/* UART Ring buffer structure */
typedef struct
{
UNS_8 tx[UART_RING_BUFSIZE]; /* UART Tx data ring buffer */
UNS_8 rx[UART_RING_BUFSIZE]; /* UART Rx data ring buffer */
INT_32 tx_head; /* UART Tx ring buffer head index */
INT_32 tx_tail; /* UART Tx ring buffer tail index */
INT_32 rx_head; /* UART Rx ring buffer head index */
INT_32 rx_tail; /* UART Rx ring buffer tail index */
} UART_RING_BUFFER_T;
/* UART device configuration structure type */
typedef struct
{
BOOL_32 init; /* Device initialized flag */
UART_RING_BUFFER_T rb; /* Device ring buffer */
UART_REGS_T *regptr; /* Pointer to UART registers */
} UART_CFG_T;
/* UART device configuration structure for UART 0 */
STATIC UART_CFG_T uart0cfg;
/* UART device configuration structure for UART 1 */
STATIC UART_CFG_T uart1cfg;
/* UART device configuration structure for UART 2 */
STATIC UART_CFG_T uart2cfg;
/***********************************************************************
* UART driver private functions
**********************************************************************/
/***********************************************************************
*
* Function: uart_standard_receive
*
* Purpose: Common UART receive function
*
* Processing:
* While the UART receive FIFO not empty status is set, read a data
* value from the FIFO and place it into the receive ring buffer
* indexed by the head pointer. Increment the head pointer and reset
* it to the start of the ring buffer if it overflows. Continue
* until the FIFO is empty.
*
* Parameters:
* uartcfg: Pointer to UART config structure
*
* Outputs: None
*
* Returns: Nothing
*
* Notes:
* There is no protection against overflowing the ring buffer.
* This function is called by UART interruption handler.
*
**********************************************************************/
STATIC void uart_standard_receive(UART_CFG_T *uartcfg)
{
UART_REGS_T *uartregs = uartcfg->regptr;
/* Continue stuffing the receive ring FIFO until the receive FIFO
is empty */
while ((uartregs->fr & UARTFR_RXFE) == 0)
{
uartcfg->rb.rx[uartcfg->rb.rx_head] =
(UNS_8) (uartregs->dr & UARTDR_DATA);
/* Increment receive ring buffer head pointer */
uartcfg->rb.rx_head++;
if (uartcfg->rb.rx_head >= UART_RING_BUFSIZE)
{
uartcfg->rb.rx_head = 0;
}
}
}
/***********************************************************************
*
* Function: uart_standard_transmit
*
* Purpose: Common UART transmit function
*
* Processing:
* While the UART transmit FIFO not full status is set and there is
* data to transmit in the ring buffer, write a data value from the
* ring buffer into the transmit FIFO. Increment the transmit ring
* buffer tail pointer and reset it to the start of the ring buffer
* if it overflows. Continue until the transmit FIFO is full or the
* ring buffer is empty. If all the data has been transmitted from
* the ring buffer, disable the transmit interrupt, otherwise
* (re)enable it.
*
* Parameters:
* uartcfg: Pointer to UART config structure
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
STATIC void uart_standard_transmit(UART_CFG_T *uartcfg)
{
UART_REGS_T *uartregs = uartcfg->regptr;
/* Continue stuffing the transmit FIFO until it is full, or until
the ring buffers are empty */
while ((uartcfg->rb.tx_head != uartcfg->rb.tx_tail)
&& ((uartregs->fr & UARTFR_TXFF) == 0))
{
/* Move a piece of data into the transmit FIFO */
uartregs->dr = (UNS_32)
uartcfg->rb.tx[uartcfg->rb.tx_tail];
/* Update transmit ring FIFO tail pointer */
uartcfg->rb.tx_tail++;
if (uartcfg->rb.tx_tail >= UART_RING_BUFSIZE)
{
uartcfg->rb.tx_tail = 0;
}
}
/* If there is no more data to send, disable the transmit
interrupt - else enable it or keep it enabled */
if (uartcfg->rb.tx_head == uartcfg->rb.tx_tail)
{
uartregs->imsc &= ~UARTINT_TX;
}
else
{
uartregs->imsc |= UARTINT_TX;
}
}
/***********************************************************************
*
* Function: uart_standard_interrupt
*
* Purpose: Common UART interrupt function
*
* Processing:
* If the UART receive interrupt or receive timeout interrupt has
* occurred, call the uart_standard_receive function. If the UART
* transmit interrupt has occurred, call the uart_standard_transmit
* function. If the UART modem status interrupt has occurred,
* disable the modem status interrupt.
*
* Parameters:
* uartcfg: Pointer to UART config structure
*
* Outputs: None
*
* Returns: Nothing
*
* Notes: None
*
**********************************************************************/
STATIC void uart_standard_interrupt(UART_CFG_T *uartcfg)
{
UART_REGS_T *uartregs = uartcfg->regptr;
/* Interrupt was due to a receive data FIFO service request */
if ((uartregs->mis & (UARTINT_RX | UARTINT_RT)) != 0)
{
uart_standard_receive(uartcfg);
}
/* Interrupt was due to a transmit data FIFO service request */
if ((uartregs->mis & UARTINT_TX) != 0)
{
uart_standard_transmit(uartcfg);
}
}
/***********************************************************************
*
* Function: uart_get_free_tx_count
*
* Purpose: Return the amount of free space in the transmit ring buffer
*
* Processing:
* Compute a count value by subtracting the transmit ring buffer
* tail index from the head index. If the value is less than 0,
* then recompute the count value adding the head index to the
* total ring buffer size minus the tail index. Return the number
* of free entries left in the ring buffer by subtracting the
* (count + 1) from the total ring buffer size.
*
* Parameters:
* uartcfg: Pointer to UART config structure
*
* Outputs: None
*
* Returns: The number of free bytes in the transmit ring buffer
*
* Notes: None
*
**********************************************************************/
STATIC INT_32 uart_get_free_tx_count(UART_CFG_T *uartcfg)
{
INT_32 count = 0;
count = uartcfg->rb.tx_head - uartcfg->rb.tx_tail;
if (count < 0)
{
/* head pointer has flipped to start of ring */
count = (UART_RING_BUFSIZE - uartcfg->rb.tx_tail) +
uartcfg->rb.tx_head;
}
return (UART_RING_BUFSIZE - count - 1);
}
/***********************************************************************
* UART driver public functions
**********************************************************************/
/***********************************************************************
*
* Function: uart_open
*
* Purpose: Open a UART
*
* Processing:
* Determine the UART configuration structure to use based on the
* paseed arg value. If the arg value doesn't match an available
* UART, return NULL to the caller. Otherwise, check the status of
* the init flag. If it is TRUE, return NULL to the caller.
* Otherwise, set init to TRUE and save the pointe to the UART
* registers. Disable the UART to clear the UART FIFOs. Re-enable
* the UART is UART mode (vs SIR mode). Disable UART interrupts.
* Set the receive and reansmit ring buffers to empty by setting
* the head and tail pointers to 0. Enable the UART is 9600-N-8-1
* mode with FIFOs enabled and return the pointer to the UART
* config structure to the caller.
*
* Parameters:
* ipbase: UART descriptor device address
* arg : Not used
*
* Outputs: None
*
* Returns: The pointer to a UART config structure or 0
*
* Notes: None
*
**********************************************************************/
INT_32 uart_open(void *ipbase, INT_32 arg)
{
UART_CFG_T *uartcfg;
/* Invalid or disabled UART */
uartcfg = (UART_CFG_T *)(0x0);
if ((UART_REGS_T *) ipbase == UART0)
{
/* UART 0 selected */
uartcfg = &uart0cfg;
}
if ((UART_REGS_T *) ipbase == UART1)
{
/* UART 1 selected */
uartcfg = &uart1cfg;
}
if ((UART_REGS_T *) ipbase == UART2)
{
/* UART 2 selected */
uartcfg = &uart2cfg;
}
if (uartcfg != (UART_CFG_T *)(0x0))
{
/* Valid UART selected, has it been previously initialized? */
if (uartcfg->init == FALSE)
{
/* Device not initialized and it is usable, so set it to
used */
uartcfg->init = TRUE;
/* Save address of register block */
uartcfg->regptr = (UART_REGS_T *) ipbase;
if ((UART_REGS_T *) ipbase == UART0)
{
/* UART0 selected */
/* Enable UART pins on muxed lines for UART0
(make sure they are not SIR) */
IOCON->uartmux = IOCON->uartmux |
(UARTMUX_U0RXD | UARTMUX_U0TXD);
/* Enable the selected UART clock in the RCPC. The
clock selection is the internal clock (14.7x MHz / 2) */
RCPC->periphclkctrl = RCPC->periphclkctrl &
~(0x1 << 0);
RCPC->periphclksel = RCPC->periphclksel &
~(0x1 << 0);
}
else if ((UART_REGS_T *) ipbase == UART1)
{
/* UART1 selected */
/* Enable UART pins on muxed lines for UART1 */
IOCON->uartmux = IOCON->uartmux |
(UARTMUX_U1RXD | UARTMUX_U1TXD);
/* Enable the selected UART clock in the RCPC. The
clock selection is the internal clock (14.7x MHz / 2) */
RCPC->periphclkctrl = RCPC->periphclkctrl &
~(0x1 << 1);
RCPC->periphclksel = RCPC->periphclksel &
~(0x1 << 1);
}
else
{
/* UART2 selected */
/* Enable UART pins on muxed lines for UART2 */
IOCON->ssimux = IOCON->ssimux |
(SSIMUX_UT2RXD | SSIMUX_UT2TXD);
/* Enable the selected UART clock in the RCPC. The
clock selection is the internal clock (14.7x MHz / 2) */
RCPC->periphclkctrl = RCPC->periphclkctrl &
~(0x1 << 2);
RCPC->periphclksel = RCPC->periphclksel &
~(0x1 << 2);
}
/* Set default baud rate as 115200 bps */
uartcfg->regptr->ibrd = UARTBRINT_115200;
uartcfg->regptr->fbrd = 0;
/* Set 1 stop bits, 8-bit word length, No parity, stick
parity disabled, FIFO enabled */
uartcfg->regptr->lcr_h = UARTLCR_FEN | UARTLCR_WLEN8;
/* Set RX and TX interrupt FIFO levels to 50% */
uartcfg->regptr->ifls = UARTIFLS_TX (2) | UARTIFLS_RX (2);
/* Clear any pending interrupts for the UART */
uartcfg->regptr->icr = (UARTINT_RX | UARTINT_TX |
UARTINT_RT | UARTINT_FE | UARTINT_PE | UARTINT_BE |
UARTINT_OE);
/* Disable all the UART interrupt by default */
uartcfg->regptr->imsc = 0;
/* Disable CTS/RTS flow control, enable receiver/
transmitter, enable UART */
uartcfg->regptr->cr = UARTCR_TXE | UARTCR_RXE |
UARTCR_ENABLE;
/* Initialize the ring buffers */
uartcfg->rb.tx_head = uartcfg->rb.tx_tail = 0;
uartcfg->rb.rx_head = uartcfg->rb.rx_tail = 0;
}
}
return (INT_32) uartcfg;
}
/***********************************************************************
*
* Function: uart_close
*
* Purpose: Close a UART
*
* Processing:
* If init is not TRUE, then return _ERROR to the caller as the
* device was not previously opened. Otherwise, disable the UART,
* set init to FALSE, and return _NO_ERROR to the caller.
*
* Parameters:
* devid: Pointer to UART config structure
*
* Outputs: None
*
* Returns: The status of the close operation
*
* Notes: None
*
**********************************************************************/
STATUS uart_close(INT_32 devid)
{
UART_CFG_T *uartcfgptr = (UART_CFG_T *) devid;
STATUS status = _ERROR;
if (uartcfgptr->init == TRUE)
{
/* Clear any pending interrupts for the UART */
uartcfgptr->regptr->icr = 0xff;
/* Disable all the UART interrupts */
uartcfgptr->regptr->imsc = 0;
/* Disable UART */
uartcfgptr->regptr->cr = 0;
if ((UART_REGS_T *) uartcfgptr->regptr == UART0)
{
/* UART0 selected */
/* Disable UART pins on muxed lines for UART0 */
IOCON->uartmux &= ~(UARTMUX_U0RXD | UARTMUX_U0TXD);
/* Disable the selected UART clock in the RCPC. */
RCPC->periphclkctrl = RCPC->periphclkctrl | (0x1 << 0);
}
else if ((UART_REGS_T *) uartcfgptr->regptr == UART1)
{
/* UART1 selected */
/* Disable UART pins on muxed lines for UART1 */
IOCON->uartmux &= ~(UARTMUX_U1RXD | UARTMUX_U1TXD);
/* Disable the selected UART clock in the RCPC. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -