📄 lh7a404_uart_driver.c
字号:
/***********************************************************************
* $Workfile: lh7a404_uart_driver.c $
* $Revision: 1.1 $
* $Author: WellsK $
* $Date: Mar 29 2004 14:58:54 $
*
* Project: LH7A404 UART driver
*
* Description:
* This file contains driver support for the UART modules on the
* LH7A404
*
* Revision History:
* $Log: //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps/lh7a404/source/lh7a404_uart_driver.c-arc $
*
* Rev 1.1 Mar 29 2004 14:58:54 WellsK
* Corrected an issue on transmit where the transmit interrupt
* would quit working if the transmit FIFO was completely filled.
*
* Rev 1.0 Jul 01 2003 12:04:26 WellsK
* 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 "lh7a404_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 1 */
#if UART_1_ENABLE == 1
STATIC UART_CFG_T uart1cfg;
#endif
/* UART device configuration structure for UART 2 */
#if UART_2_ENABLE == 1
STATIC UART_CFG_T uart2cfg;
#endif
/* UART device configuration structure for UART 3 */
#if UART_3_ENABLE == 1
STATIC UART_CFG_T uart3cfg;
#endif
/***********************************************************************
* 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.
*
**********************************************************************/
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->status & UART_STATUS_RXFE) == 0) ///==0 is not empty
{
uartcfg->rb.rx[uartcfg->rb.rx_head] =
(UNS_8) (uartregs->data & UART_DATA_MASK);
/* 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->status & UART_STATUS_TXFF) == 0))
{
/* Move a piece of data into the transmit FIFO */
uartregs->data = (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->inte &= ~UART_INTR_TI;
}
else
{
uartregs->inte |= UART_INTR_TI;
}
}
/***********************************************************************
*
* 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->intr & (UART_INTR_RTI | UART_INTR_RI)) != 0)
{
uart_standard_receive(uartcfg);
}
/* Interrupt was due to a transmit data FIFO service request */
if ((uartregs->intr & UART_INTR_TI) != 0)
{
uart_standard_transmit(uartcfg);
}
/* Interrupt was due to a modem service request */
if ((uartregs->intr & UART_INTR_MI) != 0)
{
/* Nothing to do here - add functionality as needed. For now,
just disable the interrupt so it won't happen again */
uartregs->inte &= ~UART_INTR_MI;
}
}
/***********************************************************************
*
* 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 *) NULL;
#if UART_1_ENABLE == 1
if ((UART_REGS_T *) ipbase == UART1)
{
/* UART 1 selected */
uartcfg = &uart1cfg;
}
#endif
#if UART_2_ENABLE == 1
if ((UART_REGS_T *) ipbase == UART2)
{
/* UART 2 selected */
uartcfg = &uart2cfg;
}
#endif
#if UART_3_ENABLE == 1
if ((UART_REGS_T *) ipbase == UART3)
{
/* UART 3 selected */
uartcfg = &uart3cfg;
}
#endif
if (uartcfg != (UART_CFG_T *) NULL)
{
/* 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;
/* The UART is disabled prior to enabling so the FIFOs are
empty when it is re-enabled */
uartcfg->regptr->control = UART_CNTL_SIR_DIS;
/* Enable the UART - all UART registers are reliable only
then the UART is enabled */
uartcfg->regptr->control =
(UART_CNTL_EN | UART_CNTL_SIR_DIS);
/* Disable interrupts - the interrupts remain off until
they are enabled */
uartcfg->regptr->inte = 0;
/* Initialize the ring buffers */
uartcfg->rb.tx_head = uartcfg->rb.tx_tail = 0;
uartcfg->rb.rx_head = uartcfg->rb.rx_tail = 0;
/* Set default UART configuration to FIFO enabled, 1 stop
bit, no parity, and 8 data bits */
uartcfg->regptr->lcr = (UART_LCR_WLEN8 | UART_LCR_FEN |
UART_LCR_STP1 | UART_LCR_PNONE);
/* Set default baud rate to 9600bps */
uartcfg->regptr->bcr = (UNS_32) UART_BCR_9600;
}
}
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)
{
/* Disable UART */
uartcfgptr->regptr->control = UART_CNTL_SIR_DIS;
status = _NO_ERROR;
uartcfgptr->init = FALSE;
}
return status;
}
/***********************************************************************
*
* Function: uart_ioctl
*
* Purpose: UART configuration block
*
* Processing:
* This function is a large case block. Based on the passed function
* and option values, set or get the appropriate UART parameter.
*
* Parameters:
* devid: Pointer to UART config structure
* cmd: ioctl command
* arg: ioctl argument
*
* Outputs: None
*
* Returns: The status of the ioctl operation
*
* Notes: None
*
**********************************************************************/
STATUS uart_ioctl(INT_32 devid,
INT_32 cmd,
INT_32 arg)
{
UNS_32 tmp1;
UART_REGS_T *uartregs;
UART_CFG_T *uartcfgptr = (UART_CFG_T *) devid;
STATUS status = _ERROR;
if (uartcfgptr->init == TRUE)
{
status = _NO_ERROR;
uartregs = uartcfgptr->regptr;
switch (cmd)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -