
Added initial support Xilinx Embedded Software. Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
743 lines
26 KiB
C
Executable file
743 lines
26 KiB
C
Executable file
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2002 - 2014 Xilinx, Inc. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* Use of the Software is limited solely to applications:
|
|
* (a) running on a Xilinx device, or
|
|
* (b) that interact with a Xilinx device through a bus or interconnect.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the Xilinx shall not be used
|
|
* in advertising or otherwise to promote the sale, use or other dealings in
|
|
* this Software without prior written authorization from Xilinx.
|
|
*
|
|
******************************************************************************/
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* @file xuartns550.c
|
|
*
|
|
* This file contains the required functions for the 16450/16550 UART driver.
|
|
* Refer to the header file xuartns550.h for more detailed information.
|
|
*
|
|
* <pre>
|
|
* MODIFICATION HISTORY:
|
|
*
|
|
* Ver Who Date Changes
|
|
* ----- ---- -------- -----------------------------------------------
|
|
* 1.00a ecm 08/16/01 First release
|
|
* 1.00b jhl 03/11/02 Repartitioned driver for smaller files.
|
|
* 1.00b rmm 05/14/03 Fixed diab compiler warnings relating to asserts.
|
|
* 1.01a jvb 12/13/05 I changed Initialize() into CfgInitialize(), and made
|
|
* CfgInitialize() take a pointer to a config structure
|
|
* instead of a device id. I moved Initialize() into
|
|
* xgpio_sinit.c, and had Initialize() call CfgInitialize()
|
|
* after it retrieved the config structure using the device
|
|
* id. I removed include of xparameters.h along with any
|
|
* dependencies on xparameters.h and the _g.c config table.
|
|
* 1.11a sv 03/20/07 Updated to use the new coding guidelines.
|
|
* 2.00a ktn 10/20/09 Converted all register accesses to 32 bit access.
|
|
* Updated to use HAL Processor APIs. _m is removed from the
|
|
* name of all the macro definitions. XUartNs550_mClearStats
|
|
* macro is removed, XUartNs550_ClearStats function should be
|
|
* used in its place.
|
|
* 2.01a bss 01/13/12 Removed unneccessary read of the LCR register in the
|
|
* XUartNs550_CfgInitialize function. Removed compiler
|
|
* warnings for unused variables in the
|
|
* XUartNs550_StubHandler.
|
|
* </pre>
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/***************************** Include Files ********************************/
|
|
|
|
#include "xstatus.h"
|
|
#include "xuartns550.h"
|
|
#include "xuartns550_i.h"
|
|
#include "xil_io.h"
|
|
|
|
/************************** Constant Definitions ****************************/
|
|
|
|
/* The following constant defines the amount of error that is allowed for
|
|
* a specified baud rate. This error is the difference between the actual
|
|
* baud rate that will be generated using the specified clock and the
|
|
* desired baud rate.
|
|
*/
|
|
#define XUN_MAX_BAUD_ERROR_RATE 3 /* max % error allowed */
|
|
|
|
/**************************** Type Definitions ******************************/
|
|
|
|
|
|
/***************** Macros (Inline Functions) Definitions ********************/
|
|
|
|
|
|
/************************** Variable Definitions ****************************/
|
|
|
|
|
|
/************************** Function Prototypes *****************************/
|
|
|
|
static void XUartNs550_StubHandler(void *CallBackRef, u32 Event,
|
|
unsigned int ByteCount);
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* Initializes a specific XUartNs550 instance such that it is ready to be used.
|
|
* The data format of the device is setup for 8 data bits, 1 stop bit, and no
|
|
* parity by default. The baud rate is set to a default value specified by
|
|
* Config->DefaultBaudRate if set, otherwise it is set to 19.2K baud. If the
|
|
* device has FIFOs (16550), they are enabled and the a receive FIFO threshold
|
|
* is set for 8 bytes. The default operating mode of the driver is polled mode.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
* @param Config is a reference to a structure containing information
|
|
* about a specific UART 16450/16550 device. XUartNs550_Init
|
|
* initializes an InstancePtr object for a specific device
|
|
* specified by the contents f Config. XUartNs550_Init can
|
|
* initialize multiple instance objects with the use of multiple
|
|
* calls giving different Config information on each call.
|
|
* @param EffectiveAddr is the device base address in the virtual memory
|
|
* address space. The caller is responsible for keeping the
|
|
* address mapping from EffectiveAddr to the device physical base
|
|
* address unchanged once this function is invoked. Unexpected
|
|
* errors may occur if the address mapping changes after this
|
|
* function is called. If address translation is not used,
|
|
* use Config->BaseAddress for this parameters, passing the
|
|
* physical address instead.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if initialization was successful.
|
|
* - XST_UART_BAUD_ERROR if the baud rate is not possible because
|
|
* the input clock frequency is not divisible with an acceptable
|
|
* amount of error.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
int XUartNs550_CfgInitialize(XUartNs550 *InstancePtr,
|
|
XUartNs550_Config *Config,
|
|
u32 EffectiveAddr)
|
|
{
|
|
int Status;
|
|
u32 BaudRate;
|
|
|
|
/*
|
|
* Assert validates the input arguments
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
|
|
/*
|
|
* Setup the data that is from the configuration information
|
|
*/
|
|
InstancePtr->BaseAddress = EffectiveAddr;
|
|
InstancePtr->InputClockHz = Config->InputClockHz;
|
|
|
|
/*
|
|
* Initialize the instance data to some default values and setup
|
|
* a default handler
|
|
*/
|
|
InstancePtr->Handler = XUartNs550_StubHandler;
|
|
|
|
InstancePtr->SendBuffer.NextBytePtr = NULL;
|
|
InstancePtr->SendBuffer.RemainingBytes = 0;
|
|
InstancePtr->SendBuffer.RequestedBytes = 0;
|
|
|
|
InstancePtr->ReceiveBuffer.NextBytePtr = NULL;
|
|
InstancePtr->ReceiveBuffer.RemainingBytes = 0;
|
|
InstancePtr->ReceiveBuffer.RequestedBytes = 0;
|
|
|
|
/*
|
|
* Indicate the instance is now ready to use, initialized without error
|
|
*/
|
|
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
|
|
|
|
/*
|
|
* Set the default Baud rate here, can be changed prior to
|
|
* starting the device
|
|
*/
|
|
BaudRate = Config->DefaultBaudRate;
|
|
if (! BaudRate) {
|
|
BaudRate = 19200;
|
|
}
|
|
|
|
Status = XUartNs550_SetBaudRate(InstancePtr, BaudRate);
|
|
if (Status != XST_SUCCESS) {
|
|
InstancePtr->IsReady = 0;
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set up the default format for the data, 8 bit data, 1 stop bit,
|
|
* no parity
|
|
*/
|
|
XUartNs550_SetLineControlReg(InstancePtr->BaseAddress,
|
|
XUN_FORMAT_8_BITS);
|
|
|
|
/*
|
|
* Enable the FIFOs assuming they are present and set the receive FIFO
|
|
* trigger level for 8 bytes assuming that this will work best with most
|
|
* baud rates, enabling the FIFOs also clears them, note that this must
|
|
* be done with 2 writes, 1st enabling the FIFOs then set the trigger
|
|
* level
|
|
*/
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress,
|
|
XUN_FCR_OFFSET, XUN_FIFO_ENABLE);
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_FCR_OFFSET,
|
|
XUN_FIFO_ENABLE | XUN_FIFO_RX_TRIG_MSB);
|
|
/*
|
|
* Clear the statistics for this driver
|
|
*/
|
|
XUartNs550_ClearStats(InstancePtr);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* This functions sends the specified buffer of data using the UART in either
|
|
* polled or interrupt driven modes. This function is non-blocking such that it
|
|
* will return before the data has been sent by the UART. If the UART is busy
|
|
* sending data, it will return and indicate zero bytes were sent.
|
|
*
|
|
* In a polled mode, this function will only send as much data as the UART can
|
|
* buffer, either in the transmitter or in the FIFO if present and enabled. The
|
|
* application may need to call it repeatedly to send a buffer.
|
|
*
|
|
* In interrupt mode, this function will start sending the specified buffer and
|
|
* then the interrupt handler of the driver will continue sending data until the
|
|
* buffer has been sent. A callback function, as specified by the application,
|
|
* will be called to indicate the completion of sending the buffer.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
* @param BufferPtr is pointer to a buffer of data to be sent.
|
|
* @param NumBytes contains the number of bytes to be sent. A value of
|
|
* zero will stop a previous send operation that is in progress
|
|
* in interrupt mode. Any data that was already put into the
|
|
* transmit FIFO will be sent.
|
|
*
|
|
* @return The number of bytes actually sent.
|
|
*
|
|
* @note
|
|
*
|
|
* The number of bytes is not asserted so that this function may be called with
|
|
* a value of zero to stop an operation that is already in progress.
|
|
* <br><br>
|
|
* This function and the XUartNs550_SetOptions() function modify shared data
|
|
* such that there may be a need for mutual exclusion in a multithreaded
|
|
* environment and if XUartNs550_SetOptions() if called from a handler.
|
|
*
|
|
*****************************************************************************/
|
|
unsigned int XUartNs550_Send(XUartNs550 *InstancePtr, u8 *BufferPtr,
|
|
unsigned int NumBytes)
|
|
{
|
|
unsigned int BytesSent;
|
|
u32 IerRegister;
|
|
|
|
/*
|
|
* Assert validates the input arguments
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(BufferPtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertNonvoid(((signed)NumBytes) >= 0);
|
|
|
|
/*
|
|
* Enter a critical region by disabling the UART transmit interrupts to
|
|
* allow this call to stop a previous operation that may be interrupt
|
|
* driven, only stop the transmit interrupt since this critical region
|
|
* is not really exited in the normal manner
|
|
*/
|
|
IerRegister = XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_IER_OFFSET);
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_IER_OFFSET,
|
|
IerRegister & ~XUN_IER_TX_EMPTY);
|
|
|
|
/*
|
|
* Setup the specified buffer to be sent by setting the instance
|
|
* variables so it can be sent with polled or interrupt mode
|
|
*/
|
|
InstancePtr->SendBuffer.RequestedBytes = NumBytes;
|
|
InstancePtr->SendBuffer.RemainingBytes = NumBytes;
|
|
InstancePtr->SendBuffer.NextBytePtr = BufferPtr;
|
|
|
|
/*
|
|
* Send the buffer using the UART and return the number of bytes sent
|
|
*/
|
|
|
|
BytesSent = XUartNs550_SendBuffer(InstancePtr);
|
|
|
|
/*
|
|
* The critical region is not exited in this function because of the way
|
|
* the transmit interrupts work. The other function called enables the
|
|
* tranmit interrupt such that this function can't restore a value to
|
|
* the interrupt enable register and does not need to exit the critical
|
|
* region
|
|
*/
|
|
return BytesSent;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* This function will attempt to receive a specified number of bytes of data
|
|
* from the UART and store it into the specified buffer. This function is
|
|
* designed for either polled or interrupt driven modes. It is non-blocking
|
|
* such that it will return if no data has already received by the UART.
|
|
*
|
|
* In a polled mode, this function will only receive as much data as the UART
|
|
* can buffer, either in the receiver or in the FIFO if present and enabled.
|
|
* The application may need to call it repeatedly to receive a buffer. Polled
|
|
* mode is the default mode of operation for the driver.
|
|
*
|
|
* In interrupt mode, this function will start receiving and then the interrupt
|
|
* handler of the driver will continue receiving data until the buffer has been
|
|
* received. A callback function, as specified by the application, will be called
|
|
* to indicate the completion of receiving the buffer or when any receive errors
|
|
* or timeouts occur. Interrupt mode must be enabled using the SetOptions function.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
* @param BufferPtr is pointer to buffer for data to be received into
|
|
* @param NumBytes is the number of bytes to be received. A value of zero
|
|
* will stop a previous receive operation that is in progress in
|
|
* interrupt mode.
|
|
*
|
|
* @return The number of bytes received.
|
|
*
|
|
* @note
|
|
*
|
|
* The number of bytes is not asserted so that this function may be called with
|
|
* a value of zero to stop an operation that is already in progress.
|
|
*
|
|
*****************************************************************************/
|
|
unsigned int XUartNs550_Recv(XUartNs550 *InstancePtr, u8 *BufferPtr,
|
|
unsigned int NumBytes)
|
|
{
|
|
unsigned int ReceivedCount;
|
|
u32 IerRegister;
|
|
|
|
/*
|
|
* Assert validates the input arguments
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(BufferPtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
Xil_AssertNonvoid(((signed)NumBytes) >= 0);
|
|
|
|
/*
|
|
* Enter a critical region by disabling all the UART interrupts to allow
|
|
* this call to stop a previous operation that may be interrupt driven
|
|
*/
|
|
IerRegister = XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_IER_OFFSET);
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_IER_OFFSET, 0);
|
|
|
|
/*
|
|
* Setup the specified buffer to be received by setting the instance
|
|
* variables so it can be received with polled or interrupt mode
|
|
*/
|
|
InstancePtr->ReceiveBuffer.RequestedBytes = NumBytes;
|
|
InstancePtr->ReceiveBuffer.RemainingBytes = NumBytes;
|
|
InstancePtr->ReceiveBuffer.NextBytePtr = BufferPtr;
|
|
|
|
/*
|
|
* Receive the data from the UART and return the number of bytes
|
|
* received
|
|
*/
|
|
ReceivedCount = XUartNs550_ReceiveBuffer(InstancePtr);
|
|
|
|
/*
|
|
* Restore the interrupt enable register to it's previous value such
|
|
* that the critical region is exited
|
|
*/
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_IER_OFFSET,
|
|
IerRegister);
|
|
|
|
return ReceivedCount;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* This function sends a buffer that has been previously specified by setting
|
|
* up the instance variables of the instance. This function is designed to be
|
|
* an internal function for the XUartNs550 component such that it may be called
|
|
* from a shell function that sets up the buffer or from an interrupt handler.
|
|
*
|
|
* This function sends the specified buffer of data to the UART in either
|
|
* polled or interrupt driven modes. This function is non-blocking such that
|
|
* it will return before the data has been sent by the UART.
|
|
*
|
|
* In a polled mode, this function will only send as much data as the UART can
|
|
* buffer, either in the transmitter or in the FIFO if present and enabled.
|
|
* The application may need to call it repeatedly to send a buffer.
|
|
*
|
|
* In interrupt mode, this function will start sending the specified buffer and
|
|
* then the interrupt handler of the driver will continue until the buffer
|
|
* has been sent. A callback function, as specified by the application, will
|
|
* be called to indicate the completion of sending the buffer.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
*
|
|
* @return NumBytes is the number of bytes actually sent (put into the
|
|
* UART tranmitter and/or FIFO).
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
unsigned int XUartNs550_SendBuffer(XUartNs550 *InstancePtr)
|
|
{
|
|
unsigned int SentCount = 0;
|
|
unsigned int BytesToSend = 0; /* default to not send anything */
|
|
unsigned int FifoSize;
|
|
u32 LsrRegister;
|
|
u32 IirRegister;
|
|
u32 IerRegister;
|
|
|
|
/*
|
|
* Read the line status register to determine if the transmitter is
|
|
* empty
|
|
*/
|
|
LsrRegister = XUartNs550_GetLineStatusReg(InstancePtr->BaseAddress);
|
|
|
|
/*
|
|
* If the transmitter is not empty then don't send any data, the empty
|
|
* room in the FIFO is not available
|
|
*/
|
|
if (LsrRegister & XUN_LSR_TX_BUFFER_EMPTY) {
|
|
/*
|
|
* Read the interrupt ID register to determine if FIFOs
|
|
* are enabled
|
|
*/
|
|
IirRegister = XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_IIR_OFFSET);
|
|
|
|
/*
|
|
* When there are FIFOs, send up to the FIFO size. When there
|
|
* are no FIFOs, only send 1 byte of data
|
|
*/
|
|
if (IirRegister & XUN_INT_ID_FIFOS_ENABLED) {
|
|
/*
|
|
* Determine how many bytes can be sent depending on if
|
|
* the transmitter is empty, a FIFO size of N is really
|
|
* N - 1 plus the transmitter register
|
|
*/
|
|
if (LsrRegister & XUN_LSR_TX_EMPTY) {
|
|
FifoSize = XUN_FIFO_SIZE;
|
|
} else {
|
|
FifoSize = XUN_FIFO_SIZE - 1;
|
|
}
|
|
|
|
/*
|
|
* FIFOs are enabled, if the number of bytes to send
|
|
* is less than the size of the FIFO, then send all
|
|
* bytes, otherwise fill the FIFO
|
|
*/
|
|
if (InstancePtr->SendBuffer.RemainingBytes < FifoSize) {
|
|
BytesToSend =
|
|
InstancePtr->SendBuffer.RemainingBytes;
|
|
} else {
|
|
BytesToSend = FifoSize;
|
|
}
|
|
} else if (InstancePtr->SendBuffer.RemainingBytes > 0) {
|
|
/*
|
|
* Without FIFOs, we can only send 1 byte. We needed to
|
|
* check for non-zero remaining bytes in case this
|
|
* routine was called only to kick the transmitter and
|
|
* enable the UART interrupt
|
|
*/
|
|
BytesToSend = 1;
|
|
}
|
|
|
|
/*
|
|
* Fill the FIFO if it's present or the transmitter only from
|
|
* the the buffer that was specified
|
|
*/
|
|
for (SentCount = 0; SentCount < BytesToSend; SentCount++) {
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress,
|
|
XUN_THR_OFFSET,
|
|
InstancePtr->SendBuffer.NextBytePtr[SentCount]);
|
|
}
|
|
}
|
|
/*
|
|
* Update the buffer to reflect the bytes that were sent from it
|
|
*/
|
|
InstancePtr->SendBuffer.NextBytePtr += SentCount;
|
|
InstancePtr->SendBuffer.RemainingBytes -= SentCount;
|
|
|
|
/*
|
|
* Increment associated counters
|
|
*/
|
|
InstancePtr->Stats.CharactersTransmitted += SentCount;
|
|
|
|
/*
|
|
* If interrupts are enabled as indicated by the receive interrupt, then
|
|
* enable the transmit interrupt, it is not enabled continuously because
|
|
* it causes an interrupt whenever the FIFO is empty
|
|
*/
|
|
IerRegister = XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_IER_OFFSET);
|
|
if (IerRegister & XUN_IER_RX_DATA) {
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_IER_OFFSET,
|
|
IerRegister | XUN_IER_TX_EMPTY);
|
|
}
|
|
/*
|
|
* Return the number of bytes that were sent, althought they really were
|
|
* only put into the FIFO, not completely sent yet
|
|
*/
|
|
return SentCount;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* This function receives a buffer that has been previously specified by setting
|
|
* up the instance variables of the instance. This function is designed to be
|
|
* an internal function for the XUartNs550 component such that it may be called
|
|
* from a shell function that sets up the buffer or from an interrupt handler.
|
|
*
|
|
* This function will attempt to receive a specified number of bytes of data
|
|
* from the UART and store it into the specified buffer. This function is
|
|
* designed for either polled or interrupt driven modes. It is non-blocking
|
|
* such that it will return if there is no data has already received by the
|
|
* UART.
|
|
*
|
|
* In a polled mode, this function will only receive as much data as the UART
|
|
* can buffer, either in the receiver or in the FIFO if present and enabled.
|
|
* The application may need to call it repeatedly to receive a buffer. Polled
|
|
* mode is the default mode of operation for the driver.
|
|
*
|
|
* In interrupt mode, this function will start receiving and then the interrupt
|
|
* handler of the driver will continue until the buffer has been received. A
|
|
* callback function, as specified by the application, will be called to indicate
|
|
* the completion of receiving the buffer or when any receive errors or timeouts
|
|
* occur. Interrupt mode must be enabled using the SetOptions function.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
*
|
|
* @return The number of bytes received.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
unsigned int XUartNs550_ReceiveBuffer(XUartNs550 *InstancePtr)
|
|
{
|
|
u32 LsrRegister;
|
|
unsigned int ReceivedCount = 0;
|
|
|
|
/*
|
|
* Loop until there is not more data buffered by the UART or the
|
|
* specified number of bytes is received
|
|
*/
|
|
while (ReceivedCount < InstancePtr->ReceiveBuffer.RemainingBytes) {
|
|
|
|
/*
|
|
* Read the Line Status Register to determine if there is any
|
|
* data in the receiver/FIFO
|
|
*/
|
|
LsrRegister =
|
|
XUartNs550_GetLineStatusReg(InstancePtr->BaseAddress);
|
|
|
|
/*
|
|
* If there is a break condition then a zero data byte was put
|
|
* into the receiver, just read it and dump it and update the
|
|
* stats
|
|
*/
|
|
if (LsrRegister & XUN_LSR_BREAK_INT) {
|
|
(void)XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_RBR_OFFSET);
|
|
XUartNs550_UpdateStats(InstancePtr, (u8)LsrRegister);
|
|
}
|
|
|
|
/*
|
|
* If there is data ready to be removed, then put the next byte
|
|
* received into the specified buffer and update the stats to
|
|
* reflect any receive errors for the byte
|
|
*/
|
|
else if (LsrRegister & XUN_LSR_DATA_READY) {
|
|
InstancePtr->ReceiveBuffer.NextBytePtr[ReceivedCount++] =
|
|
XUartNs550_ReadReg(InstancePtr->BaseAddress,
|
|
XUN_RBR_OFFSET);
|
|
|
|
XUartNs550_UpdateStats(InstancePtr, (u8)LsrRegister);
|
|
}
|
|
|
|
/*
|
|
* There's no more data buffered, so exit such that this
|
|
* function does not block waiting for data
|
|
*/
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update the receive buffer to reflect the number of bytes that was
|
|
* received
|
|
*/
|
|
InstancePtr->ReceiveBuffer.NextBytePtr += ReceivedCount;
|
|
InstancePtr->ReceiveBuffer.RemainingBytes -= ReceivedCount;
|
|
|
|
/*
|
|
* Increment associated counters in the statistics
|
|
*/
|
|
InstancePtr->Stats.CharactersReceived += ReceivedCount;
|
|
|
|
return ReceivedCount;
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Sets the baud rate for the specified UART. Checks the input value for
|
|
* validity and also verifies that the requested rate can be configured to
|
|
* within the 3 percent error range for RS-232 communications. If the provided
|
|
* rate is not valid, the current setting is unchanged.
|
|
*
|
|
* This function is designed to be an internal function only used within the
|
|
* XUartNs550 component. It is necessary for initialization and for the user
|
|
* available function that sets the data format.
|
|
*
|
|
* @param InstancePtr is a pointer to the XUartNs550 instance.
|
|
* @param BaudRate to be set in the hardware.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if everything configures as expected
|
|
* - XST_UART_BAUD_ERROR if the requested rate is not available
|
|
* because there was too much error due to the input clock
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
int XUartNs550_SetBaudRate(XUartNs550 *InstancePtr, u32 BaudRate)
|
|
{
|
|
|
|
u32 BaudLSB;
|
|
u32 BaudMSB;
|
|
u32 LcrRegister;
|
|
u32 Divisor;
|
|
u32 TargetRate;
|
|
u32 Error;
|
|
u32 PercentError;
|
|
|
|
/*
|
|
* Assert validates the input arguments
|
|
*/
|
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
|
|
|
/*
|
|
* Determine what the divisor should be to get the specified baud
|
|
* rater based upon the input clock frequency and a baud clock prescaler
|
|
* of 16
|
|
*/
|
|
Divisor = InstancePtr->InputClockHz / (BaudRate * 16UL);
|
|
|
|
/*
|
|
* check for too much error between the baud rate that will be generated
|
|
* using the divisor and the expected baud rate, integer division also
|
|
* truncates always positive
|
|
*/
|
|
TargetRate = Divisor * BaudRate * 16UL;
|
|
Error = InstancePtr->InputClockHz - TargetRate;
|
|
|
|
/*
|
|
* Error has total error now compute the percentage multiplied by 100 to
|
|
* avoid floating point calculations, should be less than 3% as per
|
|
* RS-232 spec
|
|
*/
|
|
PercentError = (Error * 100UL) / InstancePtr->InputClockHz;
|
|
if (PercentError > XUN_MAX_BAUD_ERROR_RATE) {
|
|
return XST_UART_BAUD_ERROR;
|
|
|
|
}
|
|
|
|
/*
|
|
* Get the least significant and most significant bytes of the divisor
|
|
* so they can be written to 2 byte registers
|
|
*/
|
|
BaudLSB = Divisor & XUN_DIVISOR_BYTE_MASK;
|
|
BaudMSB = (Divisor >> 8) & XUN_DIVISOR_BYTE_MASK;
|
|
|
|
/*
|
|
* Save the baud rate in the instance so that the get baud rate function
|
|
* won't have to calculate it from the divisor
|
|
*/
|
|
InstancePtr->BaudRate = BaudRate;
|
|
|
|
/*
|
|
* Get the line control register contents and set the divisor latch
|
|
* access bit so the baud rate can be set
|
|
*/
|
|
LcrRegister = XUartNs550_GetLineControlReg(InstancePtr->BaseAddress);
|
|
XUartNs550_SetLineControlReg(InstancePtr->BaseAddress ,
|
|
LcrRegister | XUN_LCR_DLAB);
|
|
|
|
/*
|
|
* Set the baud Divisors to set rate, the initial write of 0xFF is
|
|
* to keep the divisor from being 0 which is not recommended as per
|
|
* the NS16550D spec sheet
|
|
*/
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_DRLS_OFFSET, 0xFF);
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_DRLM_OFFSET,
|
|
BaudMSB);
|
|
XUartNs550_WriteReg(InstancePtr->BaseAddress, XUN_DRLS_OFFSET,
|
|
BaudLSB);
|
|
|
|
/*
|
|
* Clear the Divisor latch access bit, DLAB to allow nornal
|
|
* operation and write to the line control register
|
|
*/
|
|
XUartNs550_SetLineControlReg(InstancePtr->BaseAddress, LcrRegister);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/**
|
|
*
|
|
* This function is a stub handler that is the default handler such that if the
|
|
* application has not set the handler when interrupts are enabled, this
|
|
* function will be called. The function interface has to match the interface
|
|
* specified for a handler even though none of the arguments are used.
|
|
*
|
|
* @param CallBackRef is unused by this function.
|
|
* @param Event is unused by this function.
|
|
* @param ByteCount is unused by this function.
|
|
*
|
|
* @return None.
|
|
*
|
|
* @note None.
|
|
*
|
|
*****************************************************************************/
|
|
static void XUartNs550_StubHandler(void *CallBackRef, u32 Event,
|
|
unsigned int ByteCount)
|
|
{
|
|
|
|
(void) CallBackRef;
|
|
(void) Event;
|
|
(void) ByteCount;
|
|
|
|
/*
|
|
* Assert occurs always since this is a stub and should never be called
|
|
*/
|
|
Xil_AssertVoidAlways();
|
|
}
|
|
|