📄 lh79524_uart_driver.c
字号:
/***********************************************************************
* $Workfile: lh79524_uart_driver.c $
* $Revision: 1.0 $
* $Author: ZhangJ $
* $Date: Oct 20 2004 09:48:58 $
*
* Project: LH79524 CSP library
*
* Description:
* This file contains the implementation of the LH79524 UART driver
* for UARTS 0, 1 and 2.
*
*
* Revision History:
* $Log:: //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps$
*
* Rev 1.0 Oct 20 2004 09:48:58 ZhangJ
* Initial revision.
*
* Rev 1.1 Jul 20 2004 16:50:32 PattamattaD
* Updated comments.
*
* Rev 1.0 Jun 15 2004 14:01:58 PattamattaD
* Initial revision.
*
*
*
***********************************************************************
*
* Copyright (c) 2004 Sharp Microelectronics of the Americas
*
* All rights reserved
*
* 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.
*
**********************************************************************/
#include "lh79524_iocon.h"
#include "lh79524_rcpc.h"
#include "lh79524_uart_driver.h"
/* Serial driver interrupt priorities */
typedef enum
{
UART_TX_POS = 0,
UART_RX_POS,
UART_RT_POS,
UART_FE_POS,
UART_PE_POS,
UART_BE_POS,
UART_OE_POS
} UART_INT_PRIO_T;
/* Defines for the ip block base address and driver control object */
#define REGS_T UART_REGS_T
#define DRIVER_T SERIAL_T
/* Forward declarations of private methods */
static void uart0_enable (BOOL_32 enable);
static void uart1_enable (BOOL_32 enable);
static void uart2_enable (BOOL_32 enable);
static void uart0_isr (void);
static void uart1_isr (void);
static void uart2_isr (void);
static void uart_isr (void*);
static void uart_rx_isr (void*);
static void uart_tx_isr (void*);
static void uart_err_isr (void*, INT_32);
/* Table of device base addresses */
static UNS_32 driverid[N_UARTS] =
{
UART0_BASE, /* uart0 base address */
UART1_BASE, /* uart1 base address */
UART2_BASE /* uart2 base address */
};
/* Instansiations of the driver control object */
static DRIVER_T driver[N_UARTS];
/* Address of the driver control objects */
static DRIVER_T* pdriver[N_UARTS] =
{
(DRIVER_T*)&driver[0],
(DRIVER_T*)&driver[1],
(DRIVER_T*)&driver[2]
};
/* Address of the driver interrupt handlers */
static void* driver_isr[N_UARTS] =
{
(void*)uart0_isr,
(void*)uart1_isr,
(void*)uart2_isr
};
/***********************************************************************
*
* Function: uart_open
*
* Purpose:
* Initialize the specified 16C550 UART with the paramters specified.
*
* Processing:
* Sets up the device control structure for the UART.
*
* Parameters:
* uart - uart to open
* arg - XTAL System clock
*
* Outputs:
* None
*
* Returns:
* device id or 0
*
* Notes:
* None
*
**********************************************************************/
INT_32 uart_open (INT_32 ipbase, INT_32 arg)
{
DRIVER_T* pdev = NULL;
INT_32 dev_exists = FALSE;
INT_32 devid = 0;
CHAR* dst = NULL;
INT_32 idx = 0;
REGS_T* pregs = NULL;
/* Find the device in the device table */
for (devid = 0; devid < NELEMENTS(driver); devid++)
{
/* Do we have a match */
if (ipbase == driverid[devid])
{
/* Found the device */
dev_exists = TRUE;
break;
}
}
/* Check to make sure that the device exists */
if (dev_exists == FALSE)
{
return (0);
}
/* Attach to the base address of the serial device */
pdev = (DRIVER_T*)pdriver[devid];
/* Make sure the device is not already opened */
if (pdev->init == TRUE)
{
/* Device has already been opened */
return (0);
}
/* Clear the serial driver control structure */
dst = (CHAR*)pdev;
for (idx = 0; idx < sizeof (DRIVER_T); idx++)
{
*dst++ = 0;
}
/* Attach to the base address of the selected uart */
pdev->regs = (void*)driverid[devid];
pregs = (REGS_T*)pdev->regs;
/*set the XTAL system clock */
pdev->cfg.sys_clk = (UNS_32)arg;
/* Init the uart clock and pin muxing (RX/TX lines) */
switch(devid)
{
case 0:
uart0_enable(TRUE);
break;
case 1:
uart1_enable(TRUE);
break;
case 2:
uart2_enable(TRUE);
break;
}
/* Init the dma buffers */
pdev->rx_dma = NULL;
pdev->tx_dma = NULL;
/* Bind to the tx and rx ring buffers data sections */
pdev->rx_id.data = (CHAR*)&pdev->rx_data[0];
pdev->tx_id.data = (CHAR*)&pdev->tx_data[0];
/* Init the ring buffers that are to be used for buffer IO */
RING_INIT (&pdev->rx_id, NELEMENTS(pdev->rx_data));
RING_INIT (&pdev->tx_id, NELEMENTS(pdev->tx_data));
/* Mask all uart interrupts at the source */
pregs->imsc = UART_IMASK_ALL;
/* Clear any pending errors */
pregs->rsr_ecr = UART_ECR_CLEAR;
/* clear any pending interrupts */
pregs->icr = UART_CLR_ALL;
/* Install the interrupt handlers */
pdev->isr[UART_TX_POS] = (PFV)uart_tx_isr;
pdev->isr[UART_RX_POS] = (PFV)uart_rx_isr;
pdev->isr[UART_RT_POS] = (PFV)uart_rx_isr;
pdev->isr[UART_FE_POS] = (PFV)uart_err_isr;
pdev->isr[UART_PE_POS] = (PFV)uart_err_isr;
pdev->isr[UART_BE_POS] = (PFV)uart_err_isr;
pdev->isr[UART_OE_POS] = (PFV)uart_err_isr;
/* Save the default handler isr */
pdev->irq_hdlr = driver_isr[devid];
/* set the device in default config state 115200-8-N-1*/
pregs->ibrd = UART_BRINT(pdev->cfg.sys_clk, 115200);
pregs->fbrd = UART_BRFRAC(pdev->cfg.sys_clk, 115200);
pdev->cfg.baud_rate = 115200;
pregs->lcr_h = UART_LCR_WLEN8;
/* Mark the device as open */
pdev->init = TRUE;
/* return device id */
return ((INT_32)pdev);
}
/***********************************************************************
*
* Function: uart_close
*
* Purpose:
* Turn the driver off
*
* Processing:
* This routine flushes the device, disables interrupts, disables the
* device, and marks it as closed.
*
* Parameters:
* devid - device id (UART0 or UART1)
*
* Outputs:
* None
*
* Returns:
* _NO_ERROR if device is closed successfully.
* _ERROR otherwise.
*
* Notes: None
*
**********************************************************************/
STATUS uart_close (INT_32 devid)
{
STATUS status = _NO_ERROR;
INT_32 arg = 0;
INT_32 idx = 0;
CHAR* dst = NULL;
DRIVER_T* pdev = NULL;
/* Sanity check */
if (devid == 0)
{
/* device not opened or non-valid file handle */
return (_ERROR);
}
/* Bind to the device control structure */
pdev = (DRIVER_T*)devid;
/* Make sure the device is already opened */
if (pdev->init == FALSE)
{
return (_ERROR);
}
/* Flush the device */
(void) uart_ioctl (devid, UART_FLUSH, 0);
/* Disable the rx and tx sections */
(void) uart_ioctl (devid, UART_DISABLE_TX, 0);
(void) uart_ioctl (devid, UART_DISABLE_RX, 0);
/* Mask (Disable) off the interrupts */
arg = UART_INT_TX | UART_INT_RX |
UART_INT_RT | UART_INT_FE |
UART_INT_PE | UART_INT_BE |
UART_INT_OE;
uart_ioctl (devid, UART_DISABLE_INT, arg);
/* Un-install the interrupts */
pdev->isr[UART_TX_POS] = NULL;
pdev->isr[UART_RX_POS] = NULL;
pdev->isr[UART_RT_POS] = NULL;
pdev->isr[UART_FE_POS] = NULL;
pdev->isr[UART_PE_POS] = NULL;
pdev->isr[UART_BE_POS] = NULL;
pdev->isr[UART_OE_POS] = NULL;
/* Turn the device off */
(void) uart_ioctl (devid, UART_STOP, 0);
/* Disable the uart clock and pin muxing (RX/TX lines) */
switch(devid)
{
case 0:
uart0_enable(FALSE);
break;
case 1:
uart1_enable(FALSE);
break;
case 2:
uart2_enable(FALSE);
break;
}
/* Invalidate the device */
pdev->init = FALSE;
/* Clear the serial driver control structure */
dst = (CHAR*)pdev;
for (idx = 0; idx < sizeof (DRIVER_T); idx++)
{
*dst++ = 0;
}
/* Done */
return (status);
}
/***********************************************************************
*
* Function: uart_read
*
* Purpose:
* Read the specified UART data.
*
* Processing:
* Checks to see if the device is running in polled or interrupt mode.
* In polled mode data is read directly from the uart rx fifo, while
* in interrupt mode data is read from a ring buffer. Data is read
* until ring buffer is empty, the rx fifo is empty, or the max
* number of bytes has been read.
*
* Parameters:
* devid - device id (UART0 or UART1)
* buffer - data buffer
* max_bytes - maximum number of bytes to read
*
* Outputs:
* None
*
* Returns:
* n_bytes - the actual number of bytes read
*
* Notes:
* None
*
**********************************************************************/
INT_32 uart_read (INT_32 devid,
CHAR* buffer,
INT_32 max_bytes)
{
INT_32 n_bytes = 0;
DRIVER_T* pdev = NULL;
REGS_T* pregs = NULL;
/* Sanity check */
if ((buffer == NULL) || (devid == 0))
{
/* Null pointer */
return (0);
}
/* Bind to the device control structure */
pdev = (DRIVER_T*)devid;
/* Make sure the device is already opened */
if (pdev->init == FALSE)
{
return (0);
}
/* Attach to the base address of the selected uart (0 or 1) */
pregs = (REGS_T*)pdev->regs;
/* Check to see if we are in polled or interrupt mode */
if (pdev->cfg.poll_mode == TRUE)
{
/* Read data from the receive buffer */
for (n_bytes = 0; n_bytes < max_bytes; n_bytes++)
{
/* Make sure there is data in the receive fifo */
if ((pregs->fr & UART_FR_RXFE) ==
UART_FR_RXFE)
{
/* No more data */
break;
}
/* Read data from the device */
*buffer++ = pregs->dr;
}
}
else
{
/* get the data from the device */
for (n_bytes = 0; n_bytes < max_bytes; n_bytes++)
{
/* Is there data in the ring buffer */
if (RING_COUNT (&pdev->rx_id) != 0)
{
/* Add the data to the ring buffer */
RING_GETC (&pdev->rx_id, *buffer++);
}
else
{
/* break out and return the number of bytes written */
break;
}
}
}
/* return */
return (n_bytes);
}
/***********************************************************************
*
* Function: uart_write
*
* Purpose:
* Write data to the UART.
*
* Processing:
*
* Parameters:
* devid - device id (UART0 or UART1)
* buffer - data buffer
* n_bytes - number of bytes to write.
*
* Outputs:
* None
*
* Returns:
* actual_bytes - number of bytes written.
*
* Notes:
* None
*
**********************************************************************/
INT_32 uart_write (INT_32 devid,
CHAR* buffer,
INT_32 n_bytes)
{
UNS_32 actual_bytes = 0;
DRIVER_T* pdev = NULL;
REGS_T* pregs = NULL;
/* Sanity check */
if ((buffer == NULL) || (devid == 0))
{
/* Null pointer */
return (0);
}
/* Bind to the device control structure */
pdev = (DRIVER_T*)devid;
/* Make sure the device is already opened */
if (pdev->init == FALSE)
{
return (0);
}
/* Attach to the base address of the selected uart (0 or 1) */
pregs = (REGS_T*)pdev->regs;
/* Check to see if we are in polled or interrupt mode */
if (pdev->cfg.poll_mode == TRUE)
{
/* Write the data into the transmit buffer */
for (actual_bytes = 0; actual_bytes < n_bytes; actual_bytes++)
{
/* Wait for the transmit fifo to drain */
while ((pregs->fr & UART_FR_TXFF)
== UART_FR_TXFF);
/* Write the data to the device */
pregs->dr = *buffer++;
}
}
else
{
/* Lock the system irq */
/*INT_LOCK();*/
/* Clear pending interrupts */
pregs->icr = UART_INT_TX;
/* Write data into the transmit ring buffer */
for (actual_bytes = 0; actual_bytes < n_bytes; actual_bytes++)
{
/* Load the ring buffer */
RING_PUTC (&pdev->tx_id, *buffer++);
}
/* Kick start the tranasmitter */
while ( (RING_COUNT(&pdev->tx_id) != 0) &&
!(pregs->fr & UART_FR_TXFF) )
{
/* Write the data to the Tx fifo */
RING_GETC (&pdev->tx_id, pregs->dr);
}
/* UnMask (Enable) the tx interrupt */
(void) uart_ioctl
(devid, UART_ENABLE_INT, UART_INT_TX);
/* Enable the uart transmitter */
(void) uart_ioctl (devid, UART_ENABLE_TX, 0);
/* Unlock the system irq */
/*INT_UNLOCK();*/
}
/* Return number of bytes written */
return (actual_bytes);
}
/***********************************************************************
*
* Function: uart_ioctl
*
* Purpose:
* handle uart control requests.
*
* Processing: Set/resets designated state in the device.
*
*
* Parameters:
* devid - device id
* cmd - request to process
* arg - generic argument
*
* Outputs: None
*
* Returns:
* _NO_ERROR if device controlled successfully.
* _ERROR otherwise.
*
* Notes: None
*
**********************************************************************/
STATUS uart_ioctl (INT_32 devid,
INT_32 cmd,
INT_32 arg)
{
UNS_32 temp = 0;
INT_32 status = _NO_ERROR;
REGS_T* pregs = NULL;
DRIVER_T* pdev = NULL;
/* Sanity check */
if (devid == 0)
{
/* Null pointer */
return (0);
}
/* Attach to the base address of the serial device */
pdev = (DRIVER_T*)devid;
/* Make sure the device is already opened */
if (pdev->init == FALSE)
{
return (_ERROR);
}
/* Attach to the base address of the selected uart (0 or 1) */
pregs = (REGS_T*)pdev->regs;
/* Service the users request */
switch (cmd)
{
/* Get and set requests for the baud rate */
case UART_SET_BAUD_RATE:
/* Save the new baud rate */
pregs->ibrd = UART_BRINT(pdev->cfg.sys_clk,arg);
pregs->fbrd = UART_BRFRAC(pdev->cfg.sys_clk,arg);
/*
* read and write lcr_h to ensure baud
* divisors are set
*/
temp = pregs->lcr_h;
pregs->lcr_h = temp;
/* Save the config data */
pdev->cfg.baud_rate = arg;
break;
/* Get the baud rate */
case UART_GET_BAUD_RATE:
if ((void*)arg == NULL)
{
status = _ERROR;
break;
}
*(INT_32*)arg = pdev->cfg.baud_rate;
break;
/* Set tx fifo level */
case UART_SET_TX_FIFO_LVL:
temp = pregs->ifls;
temp &= UART_TX_FIFO_MASK;
temp |= ((UNS_32)arg<<0);
pregs->ifls = temp;
/* Save the config data */
pdev->cfg.tx_fifo_depth = arg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -